From 4c2743451f23baa722fb18c1666ee08dcb0eb03d Mon Sep 17 00:00:00 2001 From: Michael Breidenbach Date: Sun, 2 Oct 2022 12:15:33 +0000 Subject: [PATCH 01/90] Translated using Weblate (Swedish) Currently translated at 100.0% (1491 of 1491 strings) --- plinth/locale/sv/LC_MESSAGES/django.po | 204 ++++++++++--------------- 1 file changed, 79 insertions(+), 125 deletions(-) diff --git a/plinth/locale/sv/LC_MESSAGES/django.po b/plinth/locale/sv/LC_MESSAGES/django.po index 12d9d2444..821e39821 100644 --- a/plinth/locale/sv/LC_MESSAGES/django.po +++ b/plinth/locale/sv/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-09-26 14:19+0000\n" +"PO-Revision-Date: 2022-10-03 14:15+0000\n" "Last-Translator: Michael Breidenbach \n" "Language-Team: Swedish \n" @@ -61,10 +61,8 @@ msgid "Restoring from the backup will restore app data." msgstr "Om du återställer från säkerhetskopian återställs appdata." #: plinth/forms.py:39 -#, fuzzy -#| msgid "Repository not found" msgid "Repository to backup to" -msgstr "Databasen hittades inte" +msgstr "Repository att säkerhetskopiera till" #: plinth/forms.py:56 msgid "Select a domain name to be used with this application" @@ -1289,10 +1287,8 @@ msgid "Show apps and features that require more technical knowledge." msgstr "Visa appar och funktioner som kräver mer teknisk kunskap." #: plinth/modules/config/forms.py:104 -#, fuzzy -#| msgid "System Monitoring" msgid "System-wide logging" -msgstr "Systemövervakning" +msgstr "Systemomfattande loggning" #: plinth/modules/config/forms.py:105 msgid "Disable logging, for privacy" @@ -1857,8 +1853,6 @@ msgid "Chat Server" msgstr "Chat-Server" #: plinth/modules/ejabberd/forms.py:19 -#, fuzzy -#| msgid "Domain Names" msgid "Domain names" msgstr "Domännamn" @@ -2621,31 +2615,33 @@ msgid "" "Below is a list of opportunities for contributing to Debian. It has been " "filtered to only show packages that are installed on this system." msgstr "" +"Nedan finns en lista över möjligheter att bidra till Debian. Det har " +"filtrerats för att bara visa paket som är installerade på det här systemet." #: plinth/modules/help/templates/help_contribute.html:59 msgid "Show issues" -msgstr "" +msgstr "Visa problem" #: plinth/modules/help/templates/help_contribute.html:63 msgid "Packages that will be removed from Debian testing" -msgstr "" +msgstr "Paket som kommer att tas bort från Debian testing" #: plinth/modules/help/templates/help_contribute.html:69 #: plinth/modules/help/templates/help_contribute.html:85 msgid "source package:" -msgstr "" +msgstr "källkodspaketet:" #: plinth/modules/help/templates/help_contribute.html:80 msgid "Packages that are not in Debian testing" -msgstr "" +msgstr "Paket som inte finns i Debian testing" #: plinth/modules/help/templates/help_contribute.html:92 msgid "Good first issues for beginners" -msgstr "" +msgstr "Bra första problem för nybörjare" #: plinth/modules/help/templates/help_contribute.html:104 msgid "Issues for which the package maintainer has requested help" -msgstr "" +msgstr "Problem som paketansvarige har begärt hjälp för" #: plinth/modules/help/templates/help_feedback.html:12 #, python-format @@ -3045,16 +3041,16 @@ msgstr "" #: plinth/modules/janus/__init__.py:22 msgid "Janus is a lightweight WebRTC server." -msgstr "" +msgstr "Janus är en lättviktig WebRTC-server." #: plinth/modules/janus/__init__.py:23 msgid "A simple video conference room is included." -msgstr "" +msgstr "Ett enkelt videokonferensrum ingår." #: plinth/modules/janus/__init__.py:25 #, python-brace-format msgid "Coturn is required to use Janus." -msgstr "" +msgstr "Coturn krävs för att använda Janus." #: plinth/modules/janus/__init__.py:41 msgid "Janus" @@ -3062,11 +3058,11 @@ msgstr "Janus" #: plinth/modules/janus/__init__.py:43 msgid "Video Room" -msgstr "" +msgstr "Videorum" #: plinth/modules/janus/manifest.py:7 msgid "Janus Video Room" -msgstr "" +msgstr "Janus videorum" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 @@ -3427,14 +3423,12 @@ msgstr "" "\"example.onion\"." #: plinth/modules/mediawiki/forms.py:41 -#, fuzzy -#| msgid "Kite name" msgid "Site Name" -msgstr "Kite namn" +msgstr "Sidnamn" #: plinth/modules/mediawiki/forms.py:42 msgid "Name of the site as displayed throughout the wiki." -msgstr "" +msgstr "Namn på webbplatsen som visas i hela wiki." #: plinth/modules/mediawiki/forms.py:46 msgid "Enable public registrations" @@ -3506,10 +3500,8 @@ msgid "Domain name updated" msgstr "Domännamnet uppdaterat" #: plinth/modules/mediawiki/views.py:106 -#, fuzzy -#| msgid "Domain name updated" msgid "Site name updated" -msgstr "Domännamnet uppdaterat" +msgstr "Sidnamnet har uppdaterats" #: plinth/modules/minetest/__init__.py:35 #, python-brace-format @@ -3689,29 +3681,27 @@ msgstr "" #: plinth/modules/mumble/forms.py:40 msgid "Set a password to join the server" -msgstr "" +msgstr "Ange ett lösenord för att ansluta till servern" #: plinth/modules/mumble/forms.py:42 -#, fuzzy -#| msgid "" -#| "Set a new upload password for Coquelicot. Leave this field blank to keep " -#| "the current password." msgid "" "Set a password that is required to join the server. Leave empty to use the " "current password." msgstr "" -"Ställ in ett nytt överföringslösenord för Coquelicot. Lämna det här fältet " -"tomt för att behålla det aktuella lösenordet." +"Ange ett lösenord som krävs för att ansluta till servern. Lämna det tomt om " +"du vill använda det nuvarande lösenordet." #: plinth/modules/mumble/forms.py:48 msgid "Set the name for the root channel" -msgstr "" +msgstr "Ange namnet på rotkanalen" #: plinth/modules/mumble/forms.py:52 msgid "" "Set the name of the main channel of your mumble server. If the name was " "never changed, the channel is named Root." msgstr "" +"Ange namnet på huvudkanalen på din mumble-server. Om namnet aldrig har " +"ändrats heter kanalen Root." #: plinth/modules/mumble/manifest.py:34 msgid "Mumblefly" @@ -3726,14 +3716,12 @@ msgid "SuperUser password successfully updated." msgstr "SuperUser lösenord har uppdaterats." #: plinth/modules/mumble/views.py:48 -#, fuzzy -#| msgid "Upload password updated" msgid "Join password changed" -msgstr "Ladda upp lösenordet uppdaterat" +msgstr "Lösenordet för anslutning har ändrats" #: plinth/modules/mumble/views.py:53 msgid "Root channel name changed." -msgstr "" +msgstr "Namnet på rotkanalen har ändrats." #: plinth/modules/names/__init__.py:22 #, python-brace-format @@ -5367,13 +5355,7 @@ msgstr "" "kontrollera åtkomst och ta bort annonser och andra avskyvärda Internet Junk. " #: plinth/modules/privoxy/__init__.py:28 -#, fuzzy, python-brace-format -#| msgid "" -#| "You can use Privoxy by modifying your browser proxy settings to your " -#| "{box_name} hostname (or IP address) with port 8118. While using Privoxy, " -#| "you can see its configuration details and documentation at http://config.privoxy.org/ or http://p.p." +#, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " "{box_name} hostname (or IP address) with port 8118. Only connections from " @@ -5614,18 +5596,17 @@ msgid "" "RSS-Bridge generates RSS and Atom feeds for websites that do not have one. " "Generated feeds can be consumed by any feed reader." msgstr "" +"RSS-Bridge genererar RSS- och Atom-feeds för webbplatser som inte har en. " +"Genererade feed kan konsumeras av alla feeedläsare." #: plinth/modules/rssbridge/__init__.py:23 -#, fuzzy, python-brace-format -#| msgid "" -#| "When enabled, Tiny Tiny RSS can be accessed by any user belonging to the feed-reader group." +#, python-brace-format msgid "" "When enabled, RSS-Bridge can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"När aktiverat kan Tiny Tiny RSS nås av alla " -"användare som tillhör gruppen feed-reader." +"När RSS-Bridge är aktiverad kan den nås av varje " +"användare som tillhör feed-reader-gruppen." #: plinth/modules/rssbridge/__init__.py:27 #, python-brace-format @@ -5634,6 +5615,9 @@ msgid "" "follow various websites. When adding a feed, enable authentication and use " "your {box_name} credentials." msgstr "" +"Du kan använda RSS-Bridge med Tiny Tiny RSS för " +"att följa olika webbplatser. När du lägger till ett feed aktiverar du " +"autentisering och använder dina {box_name}-autentiseringsuppgifter." #: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 msgid "Read and subscribe to news feeds" @@ -5642,11 +5626,11 @@ msgstr "Läsa och prenumerera på nyhetsflöden" #: plinth/modules/rssbridge/__init__.py:48 #: plinth/modules/rssbridge/manifest.py:10 msgid "RSS-Bridge" -msgstr "" +msgstr "RSS-Bridge" #: plinth/modules/rssbridge/__init__.py:49 msgid "RSS Feed Generator" -msgstr "" +msgstr "RSS Feed Generator" #: plinth/modules/samba/__init__.py:27 msgid "" @@ -6980,16 +6964,13 @@ msgid "Ports" msgstr "Portar" #: plinth/modules/tor/views.py:55 -#, fuzzy -#| msgid "Error updating configuration" msgid "Updating configuration" -msgstr "Fel vid uppdatering av konfiguration" +msgstr "Uppdatera konfigurationen" #: plinth/modules/tor/views.py:72 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error configuring app: {error}" -msgstr "Installationen misslyckades: {error}" +msgstr "Fel vid konfigurering av appen: {error}" #: plinth/modules/transmission/__init__.py:23 msgid "Transmission is a BitTorrent client with a web interface." @@ -7299,22 +7280,20 @@ msgid "Show recent update logs" msgstr "Visa senaste uppdatering av loggar" #: plinth/modules/upgrades/templates/upgrades_configure.html:138 -#, fuzzy -#| msgid "Distribution upgrade enabled" msgid "Test Distribution Upgrade" -msgstr "Distributionsuppgradering aktiverad" +msgstr "Uppgradering av testdistribution" #: plinth/modules/upgrades/templates/upgrades_configure.html:140 msgid "" "This will attempt to upgrade the system from stable to testing. It " "is meant only for development use." msgstr "" +"Detta kommer att försöka uppgradera systemet från stabilt till testning. " +"Den är endast avsedd för utvecklingsanvändning." #: plinth/modules/upgrades/templates/upgrades_configure.html:150 -#, fuzzy -#| msgid "Distribution upgrade enabled" msgid "Test distribution upgrade now" -msgstr "Distributionsuppgradering aktiverad" +msgstr "Uppgradera testdistributionen nu" #: plinth/modules/upgrades/views.py:68 #, python-brace-format @@ -7350,10 +7329,8 @@ msgid "Frequent feature updates activated." msgstr "Frekventa funktionsuppdateringar aktiverade." #: plinth/modules/upgrades/views.py:223 -#, fuzzy -#| msgid "Distribution upgrade enabled" msgid "Starting distribution upgrade test." -msgstr "Distributionsuppgradering aktiverad" +msgstr "Startar distributionsuppgraderingstest." #: plinth/modules/users/__init__.py:29 msgid "" @@ -8116,21 +8093,19 @@ msgid "Generic" msgstr "Generiska" #: plinth/operation.py:116 -#, fuzzy, python-brace-format -#| msgid "Error setting hostname: {exception}" +#, python-brace-format msgid "Error: {name}: {exception_message}" -msgstr "Fel inställning av värdnamn: {exception}" +msgstr "Fel: {name}: {exception_message}" #: plinth/operation.py:119 #, python-brace-format msgid "Waiting to start: {name}" -msgstr "" +msgstr "Väntar på att starta: {name}" #: plinth/operation.py:125 -#, fuzzy, python-brace-format -#| msgid "Service disabled: {name}" +#, python-brace-format msgid "Finished: {name}" -msgstr "Tjänsten är inaktiverad: {name}" +msgstr "Avslutad: {name}" #: plinth/package.py:191 #, python-brace-format @@ -8143,10 +8118,8 @@ msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Paketet {package_name} är den senaste versionen ({latest_version})" #: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" msgid "Error running apt-get" -msgstr "Fel under säkerhetskopiering" +msgstr "Fel vid körning av apt-get" #: plinth/package.py:389 msgid "installing" @@ -8167,83 +8140,65 @@ msgstr "konfigurationsfil: {file}" #: plinth/package.py:423 plinth/package.py:448 msgid "Timeout waiting for package manager" -msgstr "" +msgstr "Timeout väntar på pakethanteraren" #: plinth/setup.py:40 -#, fuzzy -#| msgid "Install Apps" msgid "Installing app" -msgstr "Installera appar" +msgstr "Installera app" #: plinth/setup.py:42 -#, fuzzy -#| msgid "Updating..." msgid "Updating app" -msgstr "Uppdatera..." +msgstr "Uppdatera app" #: plinth/setup.py:68 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {string} {details}" +#, python-brace-format msgid "Error installing app: {string} {details}" -msgstr "Installation misslyckades: {string} {details}" +msgstr "Fel vid installation av app: {string} {details}" #: plinth/setup.py:72 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {string} {details}" +#, python-brace-format msgid "Error updating app: {string} {details}" -msgstr "Installation misslyckades: {string} {details}" +msgstr "Fel vid uppdatering av app: {string} {details}" #: plinth/setup.py:78 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error installing app: {error}" -msgstr "Installationen misslyckades: {error}" +msgstr "Fel vid installation av app: {error}" #: plinth/setup.py:81 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error updating app: {error}" -msgstr "Installationen misslyckades: {error}" +msgstr "Fel vid uppdatering av app: {error}" #: plinth/setup.py:85 -#, fuzzy -#| msgid "Application installed." msgid "App installed." -msgstr "Applikation installerad." +msgstr "App installerad." #: plinth/setup.py:87 -#, fuzzy -#| msgid "Last update" msgid "App updated" -msgstr "Senaste uppdatering" +msgstr "App uppdaterad" #: plinth/setup.py:104 -#, fuzzy -#| msgid "Install Apps" msgid "Uninstalling app" -msgstr "Installera appar" +msgstr "Avinstallera app" #: plinth/setup.py:122 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {string} {details}" +#, python-brace-format msgid "Error uninstalling app: {string} {details}" -msgstr "Installation misslyckades: {string} {details}" +msgstr "Fel vid avinstallation av app: {string} {details}" #: plinth/setup.py:128 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error uninstalling app: {error}" -msgstr "Installationen misslyckades: {error}" +msgstr "Fel vid avinstallation av appen: {error}" #: plinth/setup.py:131 -#, fuzzy -#| msgid "Application installed." msgid "App uninstalled." -msgstr "Applikation installerad." +msgstr "Appen avinstallerad." #: plinth/setup.py:451 msgid "Updating app packages" -msgstr "" +msgstr "Uppdatera appaket" #: plinth/templates/403.html:10 msgid "403 Forbidden" @@ -8604,26 +8559,25 @@ msgstr "Uppdatera" #: plinth/templates/toolbar.html:39 plinth/templates/toolbar.html:40 #: plinth/templates/uninstall.html:36 -#, fuzzy -#| msgid "Install" msgid "Uninstall" -msgstr "Installera" +msgstr "avinstallera" #: plinth/templates/uninstall.html:11 -#, fuzzy, python-format -#| msgid "Edit User %(username)s" +#, python-format msgid "Uninstall App %(app_name)s?" -msgstr "Redigera användare %(username)s" +msgstr "Avinstallera app %(app_name)s?" #: plinth/templates/uninstall.html:17 msgid "Uninstalling an app is an exprimental feature." -msgstr "" +msgstr "Att avinstallera en app är en experimentell funktion." #: plinth/templates/uninstall.html:23 msgid "" "All app data and configuration will be permanently lost. App may be " "installed freshly again." msgstr "" +"All appdata och konfiguration kommer att gå förlorad permanent. Appen kan " +"installeras på nytt igen." #: plinth/views.py:221 msgid "Setting unchanged" @@ -8632,7 +8586,7 @@ msgstr "Instänllningar oförändrade" #: plinth/views.py:401 #, python-brace-format msgid "before uninstall of {app_id}" -msgstr "" +msgstr "innan du avinstallerar {app_id}" #: plinth/web_framework.py:114 msgid "Gujarati" From 2712da4c5dd8b3a04a7f56d2111775faa7effc50 Mon Sep 17 00:00:00 2001 From: Tymofii Lytvynenko Date: Sun, 2 Oct 2022 13:21:09 +0000 Subject: [PATCH 02/90] Translated using Weblate (Ukrainian) Currently translated at 87.0% (1298 of 1491 strings) --- plinth/locale/uk/LC_MESSAGES/django.po | 59 ++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/plinth/locale/uk/LC_MESSAGES/django.po b/plinth/locale/uk/LC_MESSAGES/django.po index b2a809053..b6e2928f6 100644 --- a/plinth/locale/uk/LC_MESSAGES/django.po +++ b/plinth/locale/uk/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-10-01 13:58+0000\n" -"Last-Translator: Andrij Mizyk \n" +"PO-Revision-Date: 2022-10-03 14:15+0000\n" +"Last-Translator: Tymofii Lytvynenko \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -1605,6 +1605,13 @@ msgid "" "Internet asks for your DNS name, they will get a response with your current " "IP address." msgstr "" +"Рішення полягає в тому, щоб призначити DNS-ім'я вашій IP-адресі та " +"оновлювати DNS-ім'я кожного разу, коли ваша IP-адреса змінюється вашим " +"Інтернет-провайдером. Динамічна DNS дозволяє вам передати вашу поточну " +"публічну IP-адресу на сервер GnuDIP. Після цього сервер призначить ваше DNS-ім'я " +"новому IP, і якщо хтось з Інтернету запитає ваше DNS-ім'я, він отримає " +"відповідь з вашою поточною IP-адресою." #: plinth/modules/dynamicdns/__init__.py:41 msgid "" @@ -1613,6 +1620,11 @@ msgid "" "freedombox.org or you may find free update URL based services at freedns.afraid.org." msgstr "" +"Якщо ви шукаєте безплатний динамічний обліковий запис DNS, ви можете знайти " +"безплатну службу GnuDIP за адресою ddns.freedombox.org або ви можете знайти безплатні " +"служби на основі URL-адреси оновлення за адресою freedns.afraid.org." #: plinth/modules/dynamicdns/__init__.py:62 msgid "Dynamic DNS Client" @@ -1628,6 +1640,9 @@ msgid "" "used within the URL. For details see the update URL templates of the example " "providers." msgstr "" +"Змінні <User>, <Pass>, <Ip>, <Domain> можуть " +"використовуватися в URL-адресі. Докладніше див. шаблони оновлених URL-адрес " +"прикладів провайдерів." #: plinth/modules/dynamicdns/forms.py:22 msgid "" @@ -1635,6 +1650,9 @@ msgid "" "provider does not support the GnuDIP protocol or your provider is not listed " "you may use the update URL of your provider." msgstr "" +"Оберіть протокол оновлення відповідно до вашого провайдера. Якщо ваш " +"провайдер не підтримує протокол GnuDIP або ваш провайдер відсутній у списку, " +"ви можете використовувати URL-адресу оновлення вашого провайдера." #: plinth/modules/dynamicdns/forms.py:27 msgid "" @@ -1676,6 +1694,11 @@ msgid "" "address. The URL should simply return the IP where the client comes from " "(example: https://ddns.freedombox.org/ip/)." msgstr "" +"Необов'язкове значення. Якщо ваш {box_name} не підключений безпосередньо до " +"Інтернету (тобто підключений до NAT-маршрутизатора), ця URL-адреса " +"використовується для визначення реальної IP-адреси. URL-адреса повинна " +"просто повертати IP-адресу, з якої приходить клієнт (наприклад: https://ddns." +"freedombox.org/ip/)." #: plinth/modules/dynamicdns/forms.py:51 msgid "The username that was used when the account was created." @@ -1843,6 +1866,9 @@ msgid "" "Domains to be used by ejabberd. Note that user accounts are unique for each " "domain, and migrating users to a new domain name is not yet implemented." msgstr "" +"Домени, які будуть використовуватися ejabberd. Зверніть увагу, що облікові " +"записи користувачів є неповторюваними для кожного домену, і міграція " +"користувачів на нове доменне ім'я поки що не реалізована." #: plinth/modules/ejabberd/forms.py:26 msgid "Enable Message Archive Management" @@ -1955,6 +1981,10 @@ msgid "" "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" +"Це комплексне рішення для поштового сервера з використанням Postfix, Dovecot " +"та Rspamd. Postfix відправляє та отримує електронні листи. Dovecot дозволяє " +"поштовим клієнтам отримувати доступ до вашої поштової скриньки за допомогою " +"IMAP і POP3. Rspamd блокує спам." #: plinth/modules/email/__init__.py:30 msgid "" @@ -1963,6 +1993,11 @@ msgid "" "restrict outgoing email. Some lift the restriction after an explicit " "request. See manual page for more information." msgstr "" +"Поштовий сервер наразі не працює з багатьма безплатними доменними службами, " +"в тому числі з тими, що надаються Фундацією FreedomBox. Багато Інтернет-" +"провайдерів також обмежують вихідну електронну пошту. Деякі з них знімають " +"обмеження після явного запиту. Дивіться сторінку посібника для отримання " +"подробиць." #: plinth/modules/email/__init__.py:35 #, python-brace-format @@ -1973,6 +2008,12 @@ msgid "" "Necessary aliases such as \"postmaster\" are automatically created pointing " "to the first admin user." msgstr "" +"Кожен користувач на {box_name} отримує адресу електронної пошти на зразок " +"user@mydomain.example. Вони також отримуватимуть пошту з усіх адрес, які " +"мають вигляд user+foo@mydomain.example. Крім того, вони можуть додавати " +"псевдоніми до своєї адреси електронної пошти. Необхідні псевдоніми, такі як " +"\"postmaster\", створюються автоматично, вказуючи на першого " +"користувача-адміністратора." #: plinth/modules/email/__init__.py:41 msgid "" @@ -2150,6 +2191,10 @@ msgid "" "you may run it using the command 'service firewalld start' or in case of a " "system with systemd 'systemctl start firewalld'." msgstr "" +"Демон фаєрвола не запущено. Будь ласка, запустіть його. Фаєрвол увімкнено " +"типово на %(box_name)s. У будь-якій системі на основі Debian (наприклад, " +"%(box_name)s) ви можете запустити його за допомогою команди 'service " +"firewalld start' або у випадку системи з systemd 'systemctl start firewalld'." #: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" @@ -2215,10 +2260,13 @@ msgid "" "also be obtained by running the command \"sudo cat /var/lib/plinth/firstboot-" "wizard-secret\" on your {box_name}" msgstr "" +"Введіть таємний код, утворений під час установлення FreedomBox. Цей таємний " +"код також можна отримати, виконавши команду \"sudo cat /var/lib/plinth/" +"firstboot-wizard-secret\" на вашому {box_name}" #: plinth/modules/first_boot/forms.py:19 msgid "Firstboot Wizard Secret" -msgstr "" +msgstr "Асистент під час першого завантаження" #: plinth/modules/first_boot/templates/firstboot_complete.html:11 msgid "Setup Complete!" @@ -2529,6 +2577,11 @@ msgid "" "into your language, hosting hackathons or install fests, and by spreading " "the word." msgstr "" +"Ви можете зробити свій внесок, пишучи код, тестуючи та повідомляючи про " +"помилки, обговорюючи нові варіанти використання та застосунки, розробляючи " +"логотипи та ілюстрації, надаючи підтримку своїм колегам-користувачам, " +"перекладаючи FreedomBox та його застосунки на вашу мову, проводячи хакатони " +"або фестивалі встановлення, а також поширюючи відомості про FreedomBox." #: plinth/modules/help/templates/help_contribute.html:28 msgid "" From 6268ae17792278be60dd64a81d25ad0c089a24b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Podhoreck=C3=BD?= Date: Tue, 4 Oct 2022 08:25:58 +0000 Subject: [PATCH 03/90] Translated using Weblate (Czech) Currently translated at 100.0% (1491 of 1491 strings) --- plinth/locale/cs/LC_MESSAGES/django.po | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plinth/locale/cs/LC_MESSAGES/django.po b/plinth/locale/cs/LC_MESSAGES/django.po index 0f4dc5804..85518807a 100644 --- a/plinth/locale/cs/LC_MESSAGES/django.po +++ b/plinth/locale/cs/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-09-14 17:19+0000\n" -"Last-Translator: ikmaak \n" +"PO-Revision-Date: 2022-10-05 09:23+0000\n" +"Last-Translator: Jiří Podhorecký \n" "Language-Team: Czech \n" "Language: cs\n" @@ -17,7 +17,7 @@ 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 4.14.1-dev\n" +"X-Generator: Weblate 4.14.1\n" #: doc/dev/_templates/layout.html:11 msgid "Page source" @@ -7274,6 +7274,8 @@ msgid "" "This will attempt to upgrade the system from stable to testing. It " "is meant only for development use." msgstr "" +"Tím se pokusíte upgradovat systém ze stabilního na testovací. Je " +"určen pouze pro vývojové použití." #: plinth/modules/upgrades/templates/upgrades_configure.html:150 msgid "Test distribution upgrade now" From 4fada0a23e3a33baf0936f4492471b4401a3babe Mon Sep 17 00:00:00 2001 From: Tymofii Lytvynenko Date: Wed, 5 Oct 2022 19:30:19 +0000 Subject: [PATCH 04/90] Translated using Weblate (Ukrainian) Currently translated at 87.9% (1311 of 1491 strings) --- plinth/locale/uk/LC_MESSAGES/django.po | 49 ++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/plinth/locale/uk/LC_MESSAGES/django.po b/plinth/locale/uk/LC_MESSAGES/django.po index b6e2928f6..7d906f93e 100644 --- a/plinth/locale/uk/LC_MESSAGES/django.po +++ b/plinth/locale/uk/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-10-03 14:15+0000\n" +"PO-Revision-Date: 2022-10-06 20:22+0000\n" "Last-Translator: Tymofii Lytvynenko \n" "Language-Team: Ukrainian \n" @@ -2594,6 +2594,14 @@ msgid "" "throughout the world. The FreedomBox Foundation would not exist without its " "supporters." msgstr "" +"Ви також можете допомогти проєкту фінансово, зробивши пожертву на рахунок неприбуткової " +"організації FreedomBox Foundation. Заснована у 2011 році, FreedomBox " +"Foundation є неприбутковою організацією зі статусом 501(c)(3) зі штаб-" +"квартирою у Нью-Йорку, яка існує для підтримки проєкту FreedomBox. Вона " +"забезпечує технічну інфраструктуру та юридичні послуги для проєкту, розвиває " +"партнерські відносини та виступає на захист FreedomBox у всьому світі. " +"Фундація FreedomBox не існувала б без своїх прихильників." #: plinth/modules/help/templates/help_contribute.html:42 #: plinth/modules/power/templates/power_restart.html:27 @@ -2611,6 +2619,9 @@ msgid "" "Below is a list of opportunities for contributing to Debian. It has been " "filtered to only show packages that are installed on this system." msgstr "" +"Нижче наведено список можливостей для сприяння розвитку Debian. Він був " +"відфільтрований, щоб показати лише ті пакунки, які встановлено на цій " +"системі." #: plinth/modules/help/templates/help_contribute.html:59 msgid "Show issues" @@ -2631,11 +2642,11 @@ msgstr "Пакунки, яких нема в Debian testing" #: plinth/modules/help/templates/help_contribute.html:92 msgid "Good first issues for beginners" -msgstr "" +msgstr "Перші проблеми для початківців" #: plinth/modules/help/templates/help_contribute.html:104 msgid "Issues for which the package maintainer has requested help" -msgstr "" +msgstr "Проблеми, за якими супровідник пакета звернувся за допомогою" #: plinth/modules/help/templates/help_feedback.html:12 #, python-format @@ -2700,6 +2711,11 @@ msgid "" "\"> mailing list. The list archives also contain information about " "problems faced by other users and possible solutions." msgstr "" +"Для звернення за допомогою до спільноти %(box_name)s запити можуть бути " +"розміщені в списку розсилки. В архівах списку також містяться " +"відомості про проблеми, з якими стикалися інші користувачі, та можливі шляхи " +"їх вирішення." #: plinth/modules/help/templates/help_index.html:40 #, python-format @@ -2709,6 +2725,10 @@ msgid "" "oftc.net/?randomnick=1&channels=freedombox&prompt=1\"> #freedombox " "channel using the IRC web interface." msgstr "" +"Багато дописувачів та користувачів %(box_name)s також доступні в IRC-мережі " +"irc.oftc.net. Приєднуйтесь та звертайтеся за допомогою на каналі #freedombox за допомогою вебінтерфейсу IRC." #: plinth/modules/help/templates/help_manual.html:18 msgid "Download as PDF" @@ -2848,12 +2868,17 @@ msgid "" "For this, your browser, preferably the Tor Browser, needs to be configured " "with a proxy." msgstr "" +"I2P дозволяє анонімно переглядати Інтернет та приховані служби (eepsites). " +"Для цього ваш браузер, бажано Tor Browser, повинен бути налаштований з " +"проксі-сервером." #: plinth/modules/i2p/views.py:19 msgid "" "By default HTTP, HTTPS and IRC proxies are available. Additional proxies and " "tunnels may be configured using the tunnel configuration interface." msgstr "" +"Типово доступні HTTP, HTTPS та IRC проксі-сервери. Додаткові проксі-сервери " +"та тунелі можна налаштувати за допомогою інтерфейсу налаштування тунелів." #: plinth/modules/i2p/views.py:24 msgid "" @@ -2861,6 +2886,9 @@ msgid "" "network. Download files by adding torrents or create a new torrent to share " "a file." msgstr "" +"I2P надає застосунок для анонімного завантаження файлів в піринговій мережі. " +"Завантажуйте файли, додаючи торенти або створюйте новий торент, щоб " +"поділитися файлом." #: plinth/modules/ikiwiki/__init__.py:22 msgid "" @@ -2947,6 +2975,8 @@ msgid "" "This action will remove all the posts, pages and comments including revision " "history. Delete this wiki or blog permanently?" msgstr "" +"Ця дія видалить всі дописи, сторінки та коментарі, включаючи історію " +"редагувань. Видалити цю вікі чи блог назавжди?" #: plinth/modules/ikiwiki/views.py:74 #, python-brace-format @@ -3074,6 +3104,11 @@ msgid "" "domain. It does so by proving itself to be the owner of a domain to Let's " "Encrypt, a certificate authority (CA)." msgstr "" +"Цифровий сертифікат дозволяє користувачам мережевої служби перевіряти " +"ідентичність служби та безпечно спілкуватися з нею. {box_name} може " +"автоматично отримувати та налаштовувати цифрові сертифікати для кожного " +"доступного домену. Для цього він підтверджує, що є власником домену в Let's " +"Encrypt, центрі сертифікації (ЦС)." #: plinth/modules/letsencrypt/__init__.py:34 msgid "" @@ -3082,6 +3117,11 @@ msgid "" "read and agree with the Let's Encrypt Subscriber Agreement before using this service." msgstr "" +"Let's Encrypt - це вільний, автоматизований і відкритий центр сертифікації, " +"який працює в інтересах громадськості під керівництвом Internet Security " +"Research Group (ISRG). Будь ласка, ознайомтеся та погодьтеся з Угодою підписувача Let's Encrypt " +"перед тим, як користуватися цією службою." #: plinth/modules/letsencrypt/__init__.py:61 msgid "Let's Encrypt" @@ -3233,6 +3273,9 @@ msgid "" "a new account on your Matrix server. Disable this if you only want existing " "users to be able to use it." msgstr "" +"Увімкнення публічної реєстрації означає, що будь-хто в Інтернеті може " +"зареєструвати новий обліковий запис на вашому сервері Matrix. Вимкніть цю " +"функцію, якщо ви хочете, щоб нею могли користуватися лише наявні користувачі." #: plinth/modules/matrixsynapse/forms.py:24 #, python-brace-format From 0e326cfea31783365a92e7f0487d30dc55857454 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Tue, 27 Sep 2022 13:08:52 -0700 Subject: [PATCH 05/90] templates: Update HTML meta tags for better description and app-name - 'application-name' is not meant for regular web pages, just web apps. FreedomBox qualifies as a web app. Browsers may use this over title. - 'description' should rather talk about FreedomBox rather than just what role the web interface plays in the FreedomBox project. Tests: - Verify formatting in output HTML. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/templates/base.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plinth/templates/base.html b/plinth/templates/base.html index b431ca286..76db24170 100644 --- a/plinth/templates/base.html +++ b/plinth/templates/base.html @@ -26,9 +26,12 @@ + {% block title %} From 74678c1d69e225a9a46e29715d299e815e897843 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Sat, 1 Oct 2022 14:17:31 -0700 Subject: [PATCH 06/90] doc: dev: Minor example code refactor Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- doc/dev/tutorial/customizing.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/dev/tutorial/customizing.rst b/doc/dev/tutorial/customizing.rst index ff4eaa51d..46c2ad867 100644 --- a/doc/dev/tutorial/customizing.rst +++ b/doc/dev/tutorial/customizing.rst @@ -73,10 +73,9 @@ provide options to the user. Add the following to ``forms.py``. def __init__(self, *args, **kw): validator = DirectoryValidator(username=SYSTEM_USER, check_creatable=True) - super(TransmissionForm, - self).__init__(title=_('Download directory'), - default='/var/lib/transmission-daemon/downloads', - validator=validator, *args, **kw) + super().__init__(title=_('Download directory'), + default='/var/lib/transmission-daemon/downloads', + validator=validator, *args, **kw) This uses a utility provided by the framework and creates a Django form that shows a single option to set the download directory for our Transmission app. From 585092ca634818ed81a82d3f199ff9e52b862da2 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 2 Sep 2022 10:43:42 -0700 Subject: [PATCH 07/90] actions: Allow nested and top-level actions - Currently, privileged actions are not allowed under top-level plinth module. They are only allowed under each app module. Allow privileged actions under plinth module. - Currently, privileged actions are not allowed under a sub-module of 'privileged' package. They are allowed only in 'privileged' module. Allow sub-modules under 'privileged' package. Tests: - Email app functional tests pass - Functional tests for apps using package and service privileged methods pass Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/actions | 6 ++++- plinth/actions.py | 13 ++++++--- plinth/modules/email/privileged/__init__.py | 2 ++ plinth/tests/test_actions.py | 29 +++++---------------- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/actions/actions b/actions/actions index 1cebe5eae..c1ce7b1dd 100755 --- a/actions/actions +++ b/actions/actions @@ -59,7 +59,11 @@ def _call(module_name, action_name, arguments): raise SyntaxError('Invalid module name') cfg.read() - import_path = module_loader.get_module_import_path(module_name) + if module_name == 'plinth': + import_path = 'plinth' + else: + import_path = module_loader.get_module_import_path(module_name) + try: module = importlib.import_module(import_path + '.privileged') except ModuleNotFoundError as exception: diff --git a/plinth/actions.py b/plinth/actions.py index cb77b4fc7..68c17c241 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -84,7 +84,6 @@ import os import re import shlex import subprocess -import sys from plinth import cfg from plinth.errors import ActionError @@ -311,5 +310,13 @@ def _check_privileged_action_arguments(func): def _get_privileged_action_module_name(func): """Figure out the module name of a privileged action.""" module_name = func.__module__ - module = sys.modules[module_name] - return module.__package__.rpartition('.')[2] + while module_name: + module_name, _, last = module_name.rpartition('.') + if last == 'privileged': + break + + if not module_name: + raise ValueError('Privileged actions must be placed under a ' + 'package/module named privileged') + + return module_name.rpartition('.')[2] diff --git a/plinth/modules/email/privileged/__init__.py b/plinth/modules/email/privileged/__init__.py index 8591aa98c..999f6efc0 100644 --- a/plinth/modules/email/privileged/__init__.py +++ b/plinth/modules/email/privileged/__init__.py @@ -6,3 +6,5 @@ Provides privileged actions that run as root. from . import aliases, dkim, domain, home, postfix, spam, tls __all__ = ['aliases', 'domain', 'dkim', 'home', 'postfix', 'spam', 'tls'] + +from .aliases import action_setup diff --git a/plinth/tests/test_actions.py b/plinth/tests/test_actions.py index ca7335747..48baa6e31 100644 --- a/plinth/tests/test_actions.py +++ b/plinth/tests/test_actions.py @@ -14,13 +14,11 @@ import shutil import tempfile from unittest.mock import call, patch -import apt_pkg import pytest from plinth import cfg from plinth.actions import _log_command as log_command from plinth.actions import privileged, run, superuser_run -from plinth.errors import ActionError @pytest.fixture(autouse=True) @@ -36,7 +34,6 @@ def actions_test_setup(load_cfg): cfg.actions_dir = str(tmp_directory) actions_dir = pathlib.Path(__file__).parent / '../../actions' - shutil.copy(str(actions_dir / 'packages'), str(tmp_directory)) shutil.copy(str(actions_dir / 'test_path'), str(tmp_directory)) shutil.copy('/bin/echo', str(tmp_directory)) shutil.copy('/usr/bin/id', str(tmp_directory)) @@ -143,24 +140,6 @@ def test_multiple_options_and_output(): assert options == output -@pytest.mark.usefixtures('needs_root') -def test_is_package_manager_busy(): - """Test the behavior of `is-package-manager-busy` in both locked and - unlocked states of the dpkg lock file.""" - - apt_pkg.init() # initialize apt_pkg module - - # In the locked state, the lsof command returns 0. - # Hence no error is thrown. - with apt_pkg.SystemLock(): - superuser_run('packages', ['is-package-manager-busy']) - - # In the unlocked state, the lsof command returns 1. - # An ActionError is raised in this case. - with pytest.raises(ActionError): - superuser_run('packages', ['is-package-manager-busy']) - - @pytest.mark.usefixtures('develop_mode', 'needs_root') def test_action_path(monkeypatch): """Test that in development mode, python action scripts get the @@ -247,14 +226,16 @@ def test_privileged_argument_annotation_check(): privileged(func_valid) +@patch('plinth.actions._get_privileged_action_module_name') @patch('plinth.actions.superuser_run') -def test_privileged_method_call(superuser_run_): +def test_privileged_method_call(superuser_run_, get_module_name): """Test that privileged method calls the superuser action properly.""" def func_with_args(_a: int, _b: str, _c: int = 1, _d: str = 'dval', _e: str = 'eval'): return + get_module_name.return_value = 'tests' superuser_run_.return_value = json.dumps({ 'result': 'success', 'return': 'bar' @@ -269,13 +250,15 @@ def test_privileged_method_call(superuser_run_): [call('actions', ['tests', 'func_with_args'], input=input_.encode())]) +@patch('plinth.actions._get_privileged_action_module_name') @patch('plinth.actions.superuser_run') -def test_privileged_method_exceptions(superuser_run_): +def test_privileged_method_exceptions(superuser_run_, get_module_name): """Test that exceptions on privileged methods are return properly.""" def func_with_exception(): raise TypeError('type error') + get_module_name.return_value = 'tests' superuser_run_.return_value = json.dumps({ 'result': 'exception', 'exception': { From 6f5410931eccbd95ecc19632bb50b5111ec43d0a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Tue, 13 Sep 2022 11:12:49 -0700 Subject: [PATCH 08/90] actions: Use separate IPC for communicating results Currently privileged actions use stdout for returning the results. If any of the sub-processes accidentally output to stdout, decoding errors occur. Prevent this by opening a pipe to the privileged action and returning the output in that pipe. Tests: - Run unit tests - Functional tests for other apps pass Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/actions | 17 ++- container | 6 +- data/etc/sudoers.d/plinth | 4 +- plinth/actions.py | 121 +++++++++++++++++++-- plinth/tests/test_actions.py | 54 ++++++--- plinth/tests/test_actions_actions.py | 15 ++- vagrant-scripts/plinth-user-permissions.py | 28 ++--- 7 files changed, 190 insertions(+), 55 deletions(-) diff --git a/actions/actions b/actions/actions index c1ce7b1dd..9264b5cfe 100755 --- a/actions/actions +++ b/actions/actions @@ -8,6 +8,7 @@ import json import logging import os import sys +import traceback import typing import plinth.log @@ -26,16 +27,25 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('module', help='Module to trigger action in') parser.add_argument('action', help='Action to trigger in module') + parser.add_argument('--write-fd', type=int, default=1, + help='File descriptor to write output to') + parser.add_argument('--no-args', default=False, action='store_true', + help='Do not read arguments from stdin') args = parser.parse_args() try: try: - arguments = json.loads(sys.stdin.read()) + arguments = {'args': [], 'kwargs': {}} + if not args.no_args: + input_ = sys.stdin.read() + if input_: + arguments = json.loads(input_) except json.JSONDecodeError as exception: raise SyntaxError('Arguments on stdin not JSON.') from exception return_value = _call(args.module, args.action, arguments) - print(json.dumps(return_value)) + with os.fdopen(args.write_fd, 'w') as write_file_handle: + write_file_handle.write(json.dumps(return_value)) except PermissionError as exception: logger.error(exception.args[0]) sys.exit(EXIT_PERM) @@ -91,7 +101,8 @@ def _call(module_name, action_name, arguments): 'exception': { 'module': type(exception).__module__, 'name': type(exception).__name__, - 'args': exception.args + 'args': exception.args, + 'traceback': traceback.format_tb(exception.__traceback__) } } diff --git a/container b/container index f791f8f97..7884a2913 100755 --- a/container +++ b/container @@ -650,8 +650,10 @@ def _setup_users(image_file): str(gid), 'plinth'], stdout=subprocess.DEVNULL) logger.info('In container: Setting up sudo for users "fbx" and "plinth"') - sudo_config = 'plinth ALL=(ALL:ALL) NOPASSWD:SETENV : ' \ - '/usr/share/plinth/actions/* , /freedombox/actions/*\n' \ + sudo_config = 'Cmnd_Alias FREEDOMBOX_ACTION_DEV = /usr/share/plinth/' \ + 'actions/actions, /freedombox/actions/actions\n' \ + 'Defaults!FREEDOMBOX_ACTION_DEV closefrom_override\n' \ + 'plinth ALL=(ALL:ALL) NOPASSWD:SETENV : FREEDOMBOX_ACTION_DEV\n' \ 'fbx ALL=(ALL:ALL) NOPASSWD : ALL\n' _runc(image_file, ['tee', '/etc/sudoers.d/01-freedombox-development'], input=sudo_config.encode(), stdout=subprocess.DEVNULL) diff --git a/data/etc/sudoers.d/plinth b/data/etc/sudoers.d/plinth index 473da750a..37fbbef1b 100644 --- a/data/etc/sudoers.d/plinth +++ b/data/etc/sudoers.d/plinth @@ -2,7 +2,9 @@ # Allow plinth user to run plinth action scripts with superuser privileges # without needing a password. # -plinth ALL=(ALL:ALL) NOPASSWD:/usr/share/plinth/actions/* +Cmnd_Alias FREEDOMBOX_ACTION = /usr/share/plinth/actions/actions +Defaults!FREEDOMBOX_ACTION closefrom_override +plinth ALL=(ALL:ALL) NOPASSWD:FREEDOMBOX_ACTION # # On FreedomBox, allow all users in the 'admin' LDAP group to execute diff --git a/plinth/actions.py b/plinth/actions.py index 68c17c241..24837a2c5 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -84,6 +84,7 @@ import os import re import shlex import subprocess +import threading from plinth import cfg from plinth.errors import ActionError @@ -281,20 +282,113 @@ def privileged(func): def wrapper(*args, **kwargs): module_name = _get_privileged_action_module_name(func) action_name = func.__name__ - json_args = json.dumps({'args': args, 'kwargs': kwargs}) - return_value = superuser_run('actions', [module_name, action_name], - input=json_args.encode()) - return_value = json.loads(return_value) - if return_value['result'] == 'success': - return return_value['return'] - - module = importlib.import_module(return_value['exception']['module']) - exception = getattr(module, return_value['exception']['name']) - raise exception(*return_value['exception']['args']) + return _run_privileged_method_as_process(module_name, action_name, + args, kwargs) return wrapper +def _run_privileged_method_as_process(module_name, action_name, args, kwargs): + """Execute the privileged method in a sub-process with sudo.""" + run_as_user = kwargs.pop('_run_as_user', None) + run_in_background = kwargs.pop('_run_in_background', False) + + read_fd, write_fd = os.pipe() + os.set_inheritable(write_fd, True) + + # Prepare the command + command = ['sudo', '--non-interactive', '--close-from', str(write_fd + 1)] + if run_as_user: + command += ['--user', run_as_user] + + if cfg.develop: + command += [f'PYTHONPATH={cfg.file_root}'] + + command += [ + os.path.join(cfg.actions_dir, 'actions'), module_name, action_name, + '--write-fd', + str(write_fd) + ] + + proc_kwargs = { + 'stdin': subprocess.PIPE, + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + 'shell': False, + 'pass_fds': [write_fd], + } + if cfg.develop: + # In development mode pass on local pythonpath to access Plinth + proc_kwargs['env'] = {'PYTHONPATH': cfg.file_root} + + _log_action(module_name, action_name, run_as_user, run_in_background) + + proc = subprocess.Popen(command, **proc_kwargs) + os.close(write_fd) + + buffers = [] + # XXX: Use async to avoid creating a thread. + read_thread = threading.Thread(target=_thread_reader, + args=(read_fd, buffers)) + read_thread.start() + + wait_args = (module_name, action_name, args, kwargs, proc, command, + read_fd, read_thread, buffers) + if not run_in_background: + return _wait_for_return(*wait_args) + + wait_thread = threading.Thread(target=_wait_for_return, args=wait_args) + wait_thread.start() + + +def _wait_for_return(module_name, action_name, args, kwargs, proc, command, + read_fd, read_thread, buffers): + """Communicate with the subprocess and wait for its return.""" + log_error = kwargs.pop('_log_error', True) + json_args = json.dumps({'args': args, 'kwargs': kwargs}) + + output, error = proc.communicate(input=json_args.encode()) + read_thread.join() + if proc.returncode != 0: + logger.error('Error executing command - %s, %s, %s', command, output, + error) + raise subprocess.CalledProcessError(proc.returncode, command) + + try: + return_value = json.loads(b''.join(buffers)) + except json.JSONDecodeError: + logger.error( + 'Error decoding action return value %s..%s(*%s, **%s): %s', + module_name, action_name, args, kwargs, return_value) + raise + + if return_value['result'] == 'success': + return return_value['return'] + + module = importlib.import_module(return_value['exception']['module']) + exception_class = getattr(module, return_value['exception']['name']) + exception = exception_class(*return_value['exception']['args'], output, + error) + if log_error: + logger.error('Error running action %s..%s(*%s, **%s): %s %s %s', + module_name, action_name, args, kwargs, exception, + exception.args, return_value['exception']['traceback']) + + raise exception + + +def _thread_reader(read_fd, buffers): + """Read from the pipe in a separate thread.""" + while True: + buffer = os.read(read_fd, 10240) + if not buffer: + break + + buffers.append(buffer) + + os.close(read_fd) + + def _check_privileged_action_arguments(func): """Check that a privileged action has well defined types.""" argspec = inspect.getfullargspec(func) @@ -320,3 +414,10 @@ def _get_privileged_action_module_name(func): 'package/module named privileged') return module_name.rpartition('.')[2] + + +def _log_action(module_name, action_name, run_as_user, run_in_background): + """Log an action in a compact format.""" + prompt = f'({run_as_user})$' if run_as_user else '#' + suffix = '&' if run_in_background else '' + logger.info('%s %s..%s(…) %s', prompt, module_name, action_name, suffix) diff --git a/plinth/tests/test_actions.py b/plinth/tests/test_actions.py index 48baa6e31..ed76581a2 100644 --- a/plinth/tests/test_actions.py +++ b/plinth/tests/test_actions.py @@ -11,8 +11,9 @@ import json import os import pathlib import shutil +import subprocess import tempfile -from unittest.mock import call, patch +from unittest.mock import Mock, call, patch import pytest @@ -21,6 +22,28 @@ from plinth.actions import _log_command as log_command from plinth.actions import privileged, run, superuser_run +@pytest.fixture(name='popen') +def fixture_popen(): + """A fixture to patch subprocess.Popen called by privileged action.""" + + with patch('subprocess.Popen') as popen: + + def call_popen(command, **kwargs): + write_fd = int(command[8]) + if not isinstance(popen.called_with_write_fd, list): + popen.called_with_write_fd = [] + + popen.called_with_write_fd.append(write_fd) + os.write(write_fd, bytes(popen.return_value, encoding='utf-8')) + proc = Mock() + proc.communicate.return_value = ('', '') + proc.returncode = 0 + return proc + + popen.side_effect = call_popen + yield popen + + @pytest.fixture(autouse=True) def actions_test_setup(load_cfg): """Setup a temporary directory for testing actions. @@ -227,8 +250,7 @@ def test_privileged_argument_annotation_check(): @patch('plinth.actions._get_privileged_action_module_name') -@patch('plinth.actions.superuser_run') -def test_privileged_method_call(superuser_run_, get_module_name): +def test_privileged_method_call(get_module_name, popen): """Test that privileged method calls the superuser action properly.""" def func_with_args(_a: int, _b: str, _c: int = 1, _d: str = 'dval', @@ -236,35 +258,41 @@ def test_privileged_method_call(superuser_run_, get_module_name): return get_module_name.return_value = 'tests' - superuser_run_.return_value = json.dumps({ - 'result': 'success', - 'return': 'bar' - }) + popen.return_value = json.dumps({'result': 'success', 'return': 'bar'}) wrapped_func = privileged(func_with_args) return_value = wrapped_func(1, 'bval', None, _d='dnewval') assert return_value == 'bar' input_ = {'args': [1, 'bval', None], 'kwargs': {'_d': 'dnewval'}} input_ = json.dumps(input_) - superuser_run_.assert_has_calls( - [call('actions', ['tests', 'func_with_args'], input=input_.encode())]) + write_fd = popen.called_with_write_fd[0] + close_from_fd = str(write_fd + 1) + popen.assert_has_calls([ + call([ + 'sudo', '--non-interactive', '--close-from', close_from_fd, + cfg.actions_dir + '/actions', 'tests', 'func_with_args', + '--write-fd', + str(write_fd) + ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, shell=False, pass_fds=[write_fd]) + ]) @patch('plinth.actions._get_privileged_action_module_name') -@patch('plinth.actions.superuser_run') -def test_privileged_method_exceptions(superuser_run_, get_module_name): +def test_privileged_method_exceptions(get_module_name, popen): """Test that exceptions on privileged methods are return properly.""" def func_with_exception(): raise TypeError('type error') get_module_name.return_value = 'tests' - superuser_run_.return_value = json.dumps({ + popen.return_value = json.dumps({ 'result': 'exception', 'exception': { 'module': 'builtins', 'name': 'TypeError', - 'args': ['type error'] + 'args': ['type error'], + 'traceback': [''] } }) wrapped_func = privileged(func_with_exception) diff --git a/plinth/tests/test_actions_actions.py b/plinth/tests/test_actions_actions.py index 9a5a84673..76802f111 100644 --- a/plinth/tests/test_actions_actions.py +++ b/plinth/tests/test_actions_actions.py @@ -77,14 +77,13 @@ def test_call_syntax_checks(getuid, get_module_import_path, import_module, setattr(module, 'func', exception_func) return_value = call('test-module', 'func', {'args': [], 'kwargs': {}}) - assert return_value == { - 'result': 'exception', - 'exception': { - 'module': 'builtins', - 'name': 'RuntimeError', - 'args': ('foo exception', ) - } - } + assert return_value['result'] == 'exception' + assert return_value['exception']['module'] == 'builtins' + assert return_value['exception']['name'] == 'RuntimeError' + assert return_value['exception']['args'] == ('foo exception', ) + assert isinstance(return_value['exception']['traceback'], list) + for line in return_value['exception']['traceback']: + assert isinstance(line, str) def test_assert_valid_arguments(actions_module): diff --git a/vagrant-scripts/plinth-user-permissions.py b/vagrant-scripts/plinth-user-permissions.py index e081446c3..64ade9b4e 100755 --- a/vagrant-scripts/plinth-user-permissions.py +++ b/vagrant-scripts/plinth-user-permissions.py @@ -1,24 +1,16 @@ #!/usr/bin/python3 # -*- mode: python -*- # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Set required permissions for user "plinth" to run plinth in the development -environment. -""" +"""Set required permissions for user "plinth" to run plinth in dev setup.""" -import augeas +import pathlib -sudoers_file = '/etc/sudoers.d/plinth' -aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) +content = ''' +Cmnd_Alias FREEDOMBOX_ACTION_DEV = /usr/share/plinth/actions/actions, /vagrant/actions/actions +Defaults!FREEDOMBOX_ACTION_DEV closefrom_override +plinth ALL=(ALL:ALL) NOPASSWD:SETENV : FREEDOMBOX_ACTION_DEV +fbx ALL=(ALL:ALL) NOPASSWD : ALL +''' -# lens for shell-script config file -aug.set('/augeas/load/Shellvars/lens', 'Sudoers.lns') -aug.set('/augeas/load/Shellvars/incl[last() + 1]', sudoers_file) -aug.load() - -aug.set('/files{}/spec[1]/host_group/command[2]'.format(sudoers_file), - '/vagrant/actions/*') -aug.set('/files{}/spec[1]/host_group/command[1]/tag[2]'.format(sudoers_file), - 'SETENV') -aug.save() +sudoers_file = pathlib.Path('/etc/sudoers.d/01-freedombox-development') +sudoers_file.write_text(content) From 0dff0fc293e02c0228448e423860b0abe6084a25 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Wed, 5 Oct 2022 11:41:19 -0700 Subject: [PATCH 09/90] actions: Implement getting raw output from the process Tests: - export-tar for a backup archive works. Yields reasonable speeds > 30 MB/s. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/actions.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/plinth/actions.py b/plinth/actions.py index 24837a2c5..4c07205bb 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -292,6 +292,8 @@ def _run_privileged_method_as_process(module_name, action_name, args, kwargs): """Execute the privileged method in a sub-process with sudo.""" run_as_user = kwargs.pop('_run_as_user', None) run_in_background = kwargs.pop('_run_in_background', False) + raw_output = kwargs.pop('_raw_output', False) + log_error = kwargs.pop('_log_error', True) read_fd, write_fd = os.pipe() os.set_inheritable(write_fd, True) @@ -326,14 +328,18 @@ def _run_privileged_method_as_process(module_name, action_name, args, kwargs): proc = subprocess.Popen(command, **proc_kwargs) os.close(write_fd) + if raw_output: + input_ = json.dumps({'args': args, 'kwargs': kwargs}).encode() + return proc, read_fd, input_ + buffers = [] # XXX: Use async to avoid creating a thread. read_thread = threading.Thread(target=_thread_reader, args=(read_fd, buffers)) read_thread.start() - wait_args = (module_name, action_name, args, kwargs, proc, command, - read_fd, read_thread, buffers) + wait_args = (module_name, action_name, args, kwargs, log_error, proc, + command, read_fd, read_thread, buffers) if not run_in_background: return _wait_for_return(*wait_args) @@ -341,10 +347,9 @@ def _run_privileged_method_as_process(module_name, action_name, args, kwargs): wait_thread.start() -def _wait_for_return(module_name, action_name, args, kwargs, proc, command, - read_fd, read_thread, buffers): +def _wait_for_return(module_name, action_name, args, kwargs, log_error, proc, + command, read_fd, read_thread, buffers): """Communicate with the subprocess and wait for its return.""" - log_error = kwargs.pop('_log_error', True) json_args = json.dumps({'args': args, 'kwargs': kwargs}) output, error = proc.communicate(input=json_args.encode()) From 5a1f4b6647c2482f7f53e3c158fb5a7eafdb82ea Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Tue, 20 Sep 2022 10:26:00 -0700 Subject: [PATCH 10/90] actions: Allow actions to be called by other users There is not much additional risk by doing this. This is needed in case of some exceptional cases such as storage.validate_directory() which need to run as a different user other than root. Tests: - Directory validation works in transmission and deluge. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/actions | 3 --- plinth/tests/test_actions_actions.py | 5 ----- 2 files changed, 8 deletions(-) diff --git a/actions/actions b/actions/actions index 9264b5cfe..e012b4b3c 100755 --- a/actions/actions +++ b/actions/actions @@ -62,9 +62,6 @@ def main(): def _call(module_name, action_name, arguments): """Import the module and run action as superuser""" - if os.getuid() != 0: - raise PermissionError('This action is reserved for root') - if '.' in module_name: raise SyntaxError('Invalid module name') diff --git a/plinth/tests/test_actions_actions.py b/plinth/tests/test_actions_actions.py index 76802f111..05c18b20c 100644 --- a/plinth/tests/test_actions_actions.py +++ b/plinth/tests/test_actions_actions.py @@ -22,11 +22,6 @@ def test_call_syntax_checks(getuid, get_module_import_path, import_module, """Test that calling a method results in proper syntax checks.""" call = actions_module._call - # Test for root permissions - getuid.return_value = 1000 - with pytest.raises(PermissionError): - call('x-module', 'x-action', {}) - # Module name validation getuid.return_value = 0 with pytest.raises(SyntaxError, match='Invalid module name'): From 2bd0ef7c610f0a44e59590e6c951325b541add8a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 1 Sep 2022 14:15:09 -0700 Subject: [PATCH 11/90] config: Drop ability to set hostname on systems without systemd We depend on systemd for many things anyway and this code path is never tested. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/hostname-change | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/actions/hostname-change b/actions/hostname-change index 3b578d026..c5bdee448 100755 --- a/actions/hostname-change +++ b/actions/hostname-change @@ -3,15 +3,6 @@ hostname="$1" -if [ -d /run/systemd/system ] ; then - hostnamectl set-hostname --transient --static "$hostname" -else - echo "$hostname" > /etc/hostname - if [ -x /etc/init.d/hostname.sh ] ; then - invoke-rc.d hostname.sh start - else - service hostname start - fi -fi +hostnamectl set-hostname --transient --static "$hostname" service avahi-daemon restart From 6e1c8c30fd52903e8cb3e527579c99b24d2e23fb Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 1 Sep 2022 14:24:30 -0700 Subject: [PATCH 12/90] dynamicdns: Check action script with flake8 - When the action was converted from shell to python3, it was not removed from the exclusion list. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b11199c70..fa0ee5529 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ code-quality: stage: test needs: [] script: - - python3 -m flake8 --exclude actions/domainname-change,actions/dynamicdns,actions/hostname-change,actions/networks container plinth actions/* + - python3 -m flake8 --exclude actions/domainname-change,actions/hostname-change,actions/networks container plinth actions/* unit-tests: stage: test From fdbe537529596d3a45641a71fec8c9c472593457 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Tue, 6 Sep 2022 13:52:32 -0700 Subject: [PATCH 13/90] tests: Add fixture to help in testing privileged actions Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- conftest.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/conftest.py b/conftest.py index e84b08e08..429743bef 100644 --- a/conftest.py +++ b/conftest.py @@ -168,6 +168,41 @@ def fixture_call_action(request, capsys, actions_module): return _call_action +@pytest.fixture(name='mock_privileged') +def fixture_mock_privileged(request): + """Mock the privileged decorator to nullify its effects.""" + try: + privileged_modules_to_mock = request.module.privileged_modules_to_mock + except AttributeError: + raise AttributeError( + 'mock_privileged fixture requires "privileged_module_to_mock" ' + 'attribute at module level') + + for module_name in privileged_modules_to_mock: + module = importlib.import_module(module_name) + for name, member in module.__dict__.items(): + wrapped = getattr(member, '__wrapped__', None) + if not callable(member) or not wrapped: + continue + + if not getattr(member, '_privileged', False): + continue + + setattr(wrapped, '_original_wrapper', member) + module.__dict__[name] = wrapped + + yield + + for module_name in privileged_modules_to_mock: + module = importlib.import_module(module_name) + for name, member in module.__dict__.items(): + wrapper = getattr(member, '_original_wrapper', None) + if not callable(member) or not wrapper: + continue + + module.__dict__[name] = wrapper + + @pytest.fixture(name='splinter_screenshot_dir', scope='session') def fixture_splinter_screenshot_dir(request): """Set default screenshot directory to ./screenshots. From 3e2900b48b45c21967dbc8684665228b2ce2d401 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 2 Sep 2022 16:27:13 -0700 Subject: [PATCH 14/90] apache: Use privileged decorator for actions Tests: - Initial setup works when a new container is created - When transmission is enabled/disabled, the web configuration for it is enabled/disabled. - When radicale is enabled/disabled, the uwsgi configuration for it is enabled/disabled. - Sharing web configuration is disabled during backup and re-enabled. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/upgrades | 12 ++- plinth/modules/apache/__init__.py | 28 +++--- plinth/modules/apache/components.py | 21 ++--- .../modules/apache/privileged.py | 85 ++++++------------- .../modules/apache/tests/test_components.py | 31 +++---- plinth/modules/backups/api.py | 9 +- 6 files changed, 66 insertions(+), 120 deletions(-) rename actions/apache => plinth/modules/apache/privileged.py (68%) mode change 100755 => 100644 diff --git a/actions/upgrades b/actions/upgrades index 3f12ea4f7..66acce5dc 100755 --- a/actions/upgrades +++ b/actions/upgrades @@ -468,10 +468,9 @@ def _disable_searx() -> bool: '/etc/uwsgi/apps-enabled/searx.ini').exists() if searx_is_enabled: print('Disabling searx...', flush=True) - subprocess.run([ - '/usr/share/plinth/actions/apache', 'uwsgi-disable', '--name', - 'searx' - ], check=True) + subprocess.run( + ['/usr/share/plinth/actions/actions', 'apache', 'uwsgi_disable'], + input='{"args": ["searx"], "kwargs": {}}'.encode(), check=True) return searx_is_enabled @@ -486,9 +485,8 @@ def _update_searx(reenable=False): if reenable: print('Re-enabling searx after upgrade...', flush=True) subprocess.run([ - '/usr/share/plinth/actions/apache', 'uwsgi-enable', '--name', - 'searx' - ], check=True) + '/usr/share/plinth/actions/actions', 'apache', 'uwsgi_enable' + ], input='{"args": ["searx"], "kwargs": {}}'.encode(), check=True) def _perform_dist_upgrade(): diff --git a/plinth/modules/apache/__init__.py b/plinth/modules/apache/__init__.py index ca567090e..9d78c1e99 100644 --- a/plinth/modules/apache/__init__.py +++ b/plinth/modules/apache/__init__.py @@ -1,12 +1,10 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for Apache server. -""" +"""FreedomBox app for Apache server.""" + import os from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg from plinth.daemon import Daemon, RelatedDaemon @@ -15,6 +13,8 @@ from plinth.modules.letsencrypt.components import LetsEncrypt from plinth.package import Packages from plinth.utils import format_lazy, is_valid_user_name +from . import privileged + class ApacheApp(app_module.App): """FreedomBox app for Apache web server.""" @@ -60,9 +60,7 @@ class ApacheApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('apache', - ['setup', '--old-version', - str(old_version)]) + privileged.setup(old_version) self.enable() @@ -70,17 +68,17 @@ class ApacheApp(app_module.App): def uws_directory_of_user(user): - """Returns the directory of the given user's website.""" + """Return the directory of the given user's website.""" return '/home/{}/public_html'.format(user) def uws_url_of_user(user): - """Returns the url path of the given user's website.""" + """Return the url path of the given user's website.""" return '/~{}/'.format(user) def user_of_uws_directory(directory): - """Returns the user of a given user website directory.""" + """Return the user of a given user website directory.""" if directory.startswith('/home/'): pos_ini = 6 elif directory.startswith('home/'): @@ -97,7 +95,7 @@ def user_of_uws_directory(directory): def user_of_uws_url(url): - """Returns the user of a given user website url path.""" + """Return the user of a given user website url path.""" MISSING = -1 pos_ini = url.find('~') @@ -113,7 +111,7 @@ def user_of_uws_url(url): def uws_directory_of_url(url): - """Returns the directory of the user's website for the given url path. + """Return the directory of the user's website for the given url path. Note: It doesn't return the full OS file path to the url path! """ @@ -121,7 +119,7 @@ def uws_directory_of_url(url): def uws_url_of_directory(directory): - """Returns the url base path of the user's website for the given OS path. + """Return the url base path of the user's website for the given OS path. Note: It doesn't return the url path for the file! """ @@ -129,10 +127,10 @@ def uws_url_of_directory(directory): def get_users_with_website(): - """Returns a dictionary of users with actual website subdirectory.""" + """Return a dictionary of users with actual website subdirectory.""" def lst_sub_dirs(directory): - """Returns the list of subdirectories of the given directory.""" + """Return the list of subdirectories of the given directory.""" return [ name for name in os.listdir(directory) if os.path.isdir(os.path.join(directory, name)) diff --git a/plinth/modules/apache/components.py b/plinth/modules/apache/components.py index 7737dce5e..32449e045 100644 --- a/plinth/modules/apache/components.py +++ b/plinth/modules/apache/components.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -App component for other apps to use Apache configuration functionality. -""" +"""App component for other apps to use Apache configuration functionality.""" import re import subprocess @@ -9,7 +7,9 @@ import subprocess from django.utils.text import format_lazy from django.utils.translation import gettext_lazy -from plinth import action_utils, actions, app +from plinth import action_utils, app + +from . import privileged class Webserver(app.LeaderComponent): @@ -47,14 +47,11 @@ class Webserver(app.LeaderComponent): def enable(self): """Enable the Apache configuration.""" - actions.superuser_run( - 'apache', ['enable', '--name', self.web_name, '--kind', self.kind]) + privileged.enable(self.web_name, self.kind) def disable(self): """Disable the Apache configuration.""" - actions.superuser_run( - 'apache', - ['disable', '--name', self.web_name, '--kind', self.kind]) + privileged.disable(self.web_name, self.kind) def diagnose(self): """Check if the web path is accessible by clients. @@ -99,13 +96,11 @@ class Uwsgi(app.LeaderComponent): def enable(self): """Enable the uWSGI configuration.""" - actions.superuser_run('apache', - ['uwsgi-enable', '--name', self.uwsgi_name]) + privileged.uwsgi_enable(self.uwsgi_name) def disable(self): """Disable the uWSGI configuration.""" - actions.superuser_run('apache', - ['uwsgi-disable', '--name', self.uwsgi_name]) + privileged.uwsgi_disable(self.uwsgi_name) def is_running(self): """Return whether the uWSGI daemon is running with configuration.""" diff --git a/actions/apache b/plinth/modules/apache/privileged.py old mode 100755 new mode 100644 similarity index 68% rename from actions/apache rename to plinth/modules/apache/privileged.py index 3a69648ff..3e0f35e26 --- a/actions/apache +++ b/plinth/modules/apache/privileged.py @@ -1,48 +1,13 @@ -#!/usr/bin/python3 -# -*- mode: python -*- # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Apache web server. -""" +"""Configure Apache web server.""" -import argparse import glob import os import re import subprocess from plinth import action_utils - - -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - subparser = subparsers.add_parser('setup', help='Setup for Apache') - subparser.add_argument( - '--old-version', type=int, required=True, - help='Earlier version of the app that is already setup.') - subparser = subparsers.add_parser( - 'enable', help='Enable a site/config/module in apache') - subparser.add_argument('--name', - help='Name of the site/config/module to enable') - subparser.add_argument('--kind', choices=['site', 'config', 'module']) - subparser = subparsers.add_parser( - 'disable', help='Disable a site/config/module in apache') - subparser.add_argument('--name', - help='Name of the site/config/module to disable') - subparser.add_argument('--kind', choices=['site', 'config', 'module']) - subparser = subparsers.add_parser( - 'uwsgi-enable', help='Enable a site/config/module in UWSGI') - subparser.add_argument('--name', - help='Name of the site/config/module to enable') - subparser = subparsers.add_parser( - 'uwsgi-disable', help='Disable a site/config/module in UWSGI') - subparser.add_argument('--name', - help='Name of the site/config/module to disable') - - subparsers.required = True - return parser.parse_args() +from plinth.actions import privileged def _get_sort_key_of_version(version): @@ -87,14 +52,15 @@ def _disable_mod_php(webserver): webserver.disable('php' + version, kind='module') -def subcommand_setup(arguments): +@privileged +def setup(old_version: int): """Setup Apache configuration.""" # Regenerate the snakeoil self-signed SSL certificate. This is so that # FreedomBox images don't all have the same certificate. When FreedomBox # package is installed via apt, don't regenerate. When upgrading to newer # version of Apache FreedomBox app and setting up for the first time don't # regenerate. - if action_utils.is_disk_image() and arguments.old_version == 0: + if action_utils.is_disk_image() and old_version == 0: subprocess.run([ 'make-ssl-cert', 'generate-default-snakeoil', '--force-overwrite' ], check=True) @@ -178,34 +144,33 @@ def subcommand_setup(arguments): # TODO: Check that the (name, kind) is a managed by FreedomBox before # performing operation. -def subcommand_enable(arguments): +@privileged +def enable(name: str, kind: str): """Enable an Apache site/config/module.""" - action_utils.webserver_enable(arguments.name, arguments.kind) + _assert_kind(kind) + action_utils.webserver_enable(name, kind) -def subcommand_disable(arguments): +@privileged +def disable(name: str, kind: str): """Disable an Apache site/config/module.""" - action_utils.webserver_disable(arguments.name, arguments.kind) + _assert_kind(kind) + action_utils.webserver_disable(name, kind) -def subcommand_uwsgi_enable(arguments): +def _assert_kind(kind: str): + """Raise and exception if kind parameter has an unexpected value.""" + if kind not in ('site', 'config', 'module'): + raise ValueError('Invalid value for parameter kind') + + +@privileged +def uwsgi_enable(name: str): """Enable uWSGI configuration and reload.""" - action_utils.uwsgi_enable(arguments.name) + action_utils.uwsgi_enable(name) -def subcommand_uwsgi_disable(arguments): +@privileged +def uwsgi_disable(name: str): """Disable uWSGI configuration and reload.""" - action_utils.uwsgi_disable(arguments.name) - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() + action_utils.uwsgi_disable(name) diff --git a/plinth/modules/apache/tests/test_components.py b/plinth/modules/apache/tests/test_components.py index 7ceba4ca1..0eece880d 100644 --- a/plinth/modules/apache/tests/test_components.py +++ b/plinth/modules/apache/tests/test_components.py @@ -47,27 +47,22 @@ def test_webserver_is_enabled(webserver_is_enabled): webserver_is_enabled.assert_has_calls([call('test-config', kind='module')]) -@patch('plinth.actions.superuser_run') -def test_webserver_enable(superuser_run): +@patch('plinth.modules.apache.privileged.enable') +def test_webserver_enable(enable): """Test that enabling webserver configuration works.""" webserver = Webserver('test-webserver', 'test-config', kind='module') webserver.enable() - superuser_run.assert_has_calls([ - call('apache', ['enable', '--name', 'test-config', '--kind', 'module']) - ]) + enable.assert_has_calls([call('test-config', 'module')]) -@patch('plinth.actions.superuser_run') -def test_webserver_disable(superuser_run): +@patch('plinth.modules.apache.privileged.disable') +def test_webserver_disable(disable): """Test that disabling webserver configuration works.""" webserver = Webserver('test-webserver', 'test-config', kind='module') webserver.disable() - superuser_run.assert_has_calls([ - call('apache', - ['disable', '--name', 'test-config', '--kind', 'module']) - ]) + disable.assert_has_calls([call('test-config', 'module')]) @patch('plinth.modules.apache.components.diagnose_url') @@ -132,24 +127,22 @@ def test_uwsgi_is_enabled(uwsgi_is_enabled, service_is_enabled): assert not uwsgi.is_enabled() -@patch('plinth.actions.superuser_run') -def test_uwsgi_enable(superuser_run): +@patch('plinth.modules.apache.privileged.uwsgi_enable') +def test_uwsgi_enable(enable): """Test that enabling uwsgi configuration works.""" uwsgi = Uwsgi('test-uwsgi', 'test-config') uwsgi.enable() - superuser_run.assert_has_calls( - [call('apache', ['uwsgi-enable', '--name', 'test-config'])]) + enable.assert_has_calls([call('test-config')]) -@patch('plinth.actions.superuser_run') -def test_uwsgi_disable(superuser_run): +@patch('plinth.modules.apache.privileged.uwsgi_disable') +def test_uwsgi_disable(disable): """Test that disabling uwsgi configuration works.""" uwsgi = Uwsgi('test-uwsgi', 'test-config') uwsgi.disable() - superuser_run.assert_has_calls( - [call('apache', ['uwsgi-disable', '--name', 'test-config'])]) + disable.assert_has_calls([call('test-config')]) @patch('plinth.action_utils.service_is_running') diff --git a/plinth/modules/backups/api.py b/plinth/modules/backups/api.py index 336ad1948..d2be5ca41 100644 --- a/plinth/modules/backups/api.py +++ b/plinth/modules/backups/api.py @@ -15,6 +15,7 @@ import logging from plinth import action_utils, actions from plinth import app as app_module from plinth import setup +from plinth.modules.apache import privileged as apache_privileged from .components import BackupRestore @@ -340,16 +341,12 @@ class ApacheServiceHandler(ServiceHandler): self.was_enabled = action_utils.webserver_is_enabled( self.web_name, kind=self.kind) if self.was_enabled: - actions.superuser_run( - 'apache', - ['disable', '--name', self.web_name, '--kind', self.kind]) + apache_privileged.disable(self.web_name, self.kind) def restart(self): """Restart the service if it was earlier running.""" if self.was_enabled: - actions.superuser_run( - 'apache', - ['enable', '--name', self.web_name, '--kind', self.kind]) + apache_privileged.enable(self.web_name, self.kind) def _shutdown_services(components): From 212364ba2ac78b61ee7b76059d4098c9fda447de Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 15:53:11 -0700 Subject: [PATCH 15/90] bepasty: Use privileged decorator for actions Tests: - Functional tests - Initial setup - Sets the domain to freedombox.local (SITENAME) - Default permissions are set to read - Three passwords with varying permissions are create by default - Current configuration is retrieved properly (default permissions, passwords) - Adding passwords works, they are list as expected - With or without comment - Removing password works - Setting default permissions works - Untested: - Upgrade from version 1 Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/bepasty/__init__.py | 43 ++------- .../modules/bepasty/privileged.py | 87 ++++--------------- plinth/modules/bepasty/views.py | 25 +++--- 3 files changed, 34 insertions(+), 121 deletions(-) rename actions/bepasty => plinth/modules/bepasty/privileged.py (64%) mode change 100755 => 100644 diff --git a/plinth/modules/bepasty/__init__.py b/plinth/modules/bepasty/__init__.py index e97e8caf9..d02b8139b 100644 --- a/plinth/modules/bepasty/__init__.py +++ b/plinth/modules/bepasty/__init__.py @@ -1,13 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for bepasty. -""" - -import json +"""FreedomBox app for bepasty.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.modules.apache.components import Uwsgi, Webserver @@ -15,7 +10,7 @@ from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.package import Packages -from . import manifest +from . import manifest, privileged _description = [ _('bepasty is a web application that allows large files to be uploaded ' @@ -97,38 +92,10 @@ class BepastyApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('bepasty', - ['setup', '--domain-name', 'freedombox.local']) + privileged.setup('freedombox.local') self.enable() - if old_version == 1 and not get_configuration().get( + if old_version == 1 and not privileged.get_configuration().get( 'DEFAULT_PERMISSIONS'): # Upgrade to a better default only if user hasn't changed the # value. - set_default_permissions('read') - - -def get_configuration(): - """Get a full configuration including passwords and defaults.""" - output = actions.superuser_run('bepasty', ['get-configuration']) - return json.loads(output) - - -def add_password(permissions, comment=None): - """Generate a password with given permissions.""" - command = ['add-password', '--permissions'] + permissions - if comment: - command += ['--comment', comment] - - actions.superuser_run('bepasty', command) - - -def remove_password(password): - """Remove a password and its permissions.""" - actions.superuser_run('bepasty', ['remove-password'], - input=password.encode()) - - -def set_default_permissions(permissions): - """Set default permissions.""" - perm = permissions.split() - actions.superuser_run('bepasty', ['set-default', '--permissions'] + perm) + privileged.set_default(['read']) diff --git a/actions/bepasty b/plinth/modules/bepasty/privileged.py old mode 100755 new mode 100644 similarity index 64% rename from actions/bepasty rename to plinth/modules/bepasty/privileged.py index b8bf179a0..4c28ec803 --- a/actions/bepasty +++ b/plinth/modules/bepasty/privileged.py @@ -1,10 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for bepasty. -""" +"""Configuration helper for bepasty.""" -import argparse import collections import grp import json @@ -15,11 +11,12 @@ import secrets import shutil import string import subprocess -import sys +from typing import Optional import augeas from plinth import action_utils +from plinth.actions import privileged from plinth.modules import bepasty DATA_DIR = '/var/lib/bepasty' @@ -29,42 +26,6 @@ PASSWORD_LENGTH = 20 CONF_FILE = pathlib.Path('/etc/bepasty-freedombox.conf') -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - setup = subparsers.add_parser( - 'setup', help='Perform post-installation operations for bepasty') - setup.add_argument('--domain-name', required=True, - help='The domain name that will be used by bepasty') - - subparsers.add_parser('get-configuration', help='Get all configuration') - - add_password = subparsers.add_parser( - 'add-password', help='Generate a password with given permissions') - add_password.add_argument( - '--permissions', nargs='+', - help='Any number of permissions from the set: {}'.format(', '.join( - bepasty.PERMISSIONS.keys()))) - add_password.add_argument( - '--comment', required=False, - help='A comment for the password and its permissions') - - subparsers.add_parser('remove-password', - help='Remove a password and its permissions') - - set_default = subparsers.add_parser('set-default', - help='Set default permissions') - set_default.add_argument( - '--permissions', nargs='*', - help='Any number of permissions from the set: {}'.format(', '.join( - bepasty.PERMISSIONS.keys()))) - - subparsers.required = True - return parser.parse_args() - - def _augeas_load(): """Initialize Augeas.""" aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + @@ -104,7 +65,8 @@ def conf_file_write(conf): aug.save() -def subcommand_setup(arguments): +@privileged +def setup(domain_name: str): """Post installation actions for bepasty.""" # Create bepasty group if needed. try: @@ -135,7 +97,7 @@ def subcommand_setup(arguments): 'the original configuration format is supported. Each line ' 'should be in KEY = VALUE format. VALUE must be a JSON ' 'encoded string.', - 'SITENAME': arguments.domain_name, + 'SITENAME': domain_name, 'STORAGE_FILESYSTEM_DIRECTORY': '/var/lib/bepasty', 'SECRET_KEY': secrets.token_hex(64), 'PERMISSIONS': { @@ -155,29 +117,30 @@ def subcommand_setup(arguments): shutil.chown(CONF_FILE, user='bepasty', group='bepasty') -def subcommand_get_configuration(_): +@privileged +def get_configuration() -> dict[str, object]: """Get default permissions, passwords, permissions and comments.""" - conf = conf_file_read() - print(json.dumps(conf)) + return conf_file_read() -def subcommand_add_password(arguments): +@privileged +def add_password(permissions: list[str], comment: Optional[str] = None): """Generate a password with given permissions.""" conf = conf_file_read() - permissions = _format_permissions(arguments.permissions) + permissions = _format_permissions(permissions) password = _generate_password() conf['PERMISSIONS'][password] = permissions - if arguments.comment: - conf['PERMISSION_COMMENTS'][password] = arguments.comment + if comment: + conf['PERMISSION_COMMENTS'][password] = comment conf_file_write(conf) action_utils.service_try_restart('uwsgi') -def subcommand_remove_password(_arguments): +@privileged +def remove_password(password: str): """Remove a password and its permissions.""" conf = conf_file_read() - password = ''.join(sys.stdin) if password in conf['PERMISSIONS']: del conf['PERMISSIONS'][password] @@ -187,9 +150,10 @@ def subcommand_remove_password(_arguments): action_utils.service_try_restart('uwsgi') -def subcommand_set_default(arguments): +@privileged +def set_default(permissions: list[str]): """Set default permissions.""" - conf = {'DEFAULT_PERMISSIONS': _format_permissions(arguments.permissions)} + conf = {'DEFAULT_PERMISSIONS': _format_permissions(permissions)} conf_file_write(conf) action_utils.service_try_restart('uwsgi') @@ -204,16 +168,3 @@ def _generate_password(): """Generate a random password.""" alphabet = string.ascii_letters + string.digits return ''.join(secrets.choice(alphabet) for _ in range(PASSWORD_LENGTH)) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/bepasty/views.py b/plinth/modules/bepasty/views.py index 74da52ac8..58347099c 100644 --- a/plinth/modules/bepasty/views.py +++ b/plinth/modules/bepasty/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the bepasty app. -""" +"""Views for the bepasty app.""" from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin @@ -11,10 +9,9 @@ from django.utils.translation import gettext_lazy as _ from django.views.decorators.http import require_POST from django.views.generic import FormView -from plinth.errors import ActionError -from plinth.modules import bepasty from plinth.views import AppView +from . import privileged from .forms import AddPasswordForm, SetDefaultPermissionsForm # i18n for permission comments @@ -27,6 +24,7 @@ PERMISSION_COMMENTS_STRINGS = { class BepastyView(AppView): """Serve configuration page.""" + app_id = 'bepasty' form_class = SetDefaultPermissionsForm template_name = 'bepasty.html' @@ -39,7 +37,7 @@ class BepastyView(AppView): def _get_configuration(self): """Return the current configuration.""" if not self.conf: - self.conf = bepasty.get_configuration() + self.conf = privileged.get_configuration() return self.conf @@ -85,10 +83,10 @@ class BepastyView(AppView): if old_data['default_permissions'] != form_data['default_permissions']: try: - bepasty.set_default_permissions( - form_data['default_permissions']) + privileged.set_default( + form_data['default_permissions'].split(' ')) messages.success(self.request, _('Configuration updated.')) - except ActionError: + except Exception: messages.error(self.request, _('An error occurred during configuration.')) @@ -112,17 +110,14 @@ class AddPasswordView(SuccessMessageMixin, FormView): def form_valid(self, form): """Add the password on valid form submission.""" - _add_password(form.cleaned_data) + form_data = form.cleaned_data + privileged.add_password(form_data['permissions'], form_data['comment']) return super().form_valid(form) -def _add_password(form_data): - bepasty.add_password(form_data['permissions'], form_data['comment']) - - @require_POST def remove(request, password): """View to remove a password.""" - bepasty.remove_password(password) + privileged.remove_password(password) messages.success(request, _('Password deleted.')) return redirect(reverse_lazy('bepasty:index')) From cdb04bb46acf61e77073839ac4abc2a304f9352f Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 16:00:54 -0700 Subject: [PATCH 16/90] bind: Use privileged decorator for actions Tests: - Initial setup: - Creates zones directory - Write default configuration - named is restarted - Forwarders - Setting forwarders works as expected. - Current list of forwarders is shown as expected - List of served domains is shown properly Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/bind | 62 -------- plinth/modules/bind/__init__.py | 184 +---------------------- plinth/modules/bind/privileged.py | 198 +++++++++++++++++++++++++ plinth/modules/bind/tests/test_bind.py | 43 +++--- plinth/modules/bind/views.py | 27 ++-- 5 files changed, 231 insertions(+), 283 deletions(-) delete mode 100755 actions/bind create mode 100644 plinth/modules/bind/privileged.py diff --git a/actions/bind b/actions/bind deleted file mode 100755 index c92df72f4..000000000 --- a/actions/bind +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for BIND server. -""" - -import argparse -from pathlib import Path - -from plinth import action_utils -from plinth.modules.bind import (CONFIG_FILE, DEFAULT_CONFIG, ZONES_DIR, - set_dnssec, set_forwarders) - - -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - setup = subparsers.add_parser('setup', help='Setup for BIND') - setup.add_argument( - '--old-version', type=int, required=True, - help='Earlier version of the app that is already setup.') - - configure = subparsers.add_parser('configure', help='Configure BIND') - configure.add_argument('--forwarders', - help='List of IP addresses, separated by space') - configure.add_argument('--dnssec', choices=['enable', 'disable'], - help='Enable or disable DNSSEC') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_setup(arguments): - """Setup BIND configuration.""" - if arguments.old_version == 0: - with open(CONFIG_FILE, 'w', encoding='utf-8') as conf_file: - conf_file.write(DEFAULT_CONFIG) - - Path(ZONES_DIR).mkdir(exist_ok=True, parents=True) - - action_utils.service_restart('named') - - -def subcommand_configure(arguments): - """Configure BIND.""" - set_forwarders(arguments.forwarders) - set_dnssec(arguments.dnssec) - action_utils.service_restart('named') - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/bind/__init__.py b/plinth/modules/bind/__init__.py index ff61d51f4..326b64086 100644 --- a/plinth/modules/bind/__init__.py +++ b/plinth/modules/bind/__init__.py @@ -1,16 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure BIND server. -""" +"""FreedomBox app to configure BIND server.""" -import re -from collections import defaultdict -from pathlib import Path - -import augeas from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import Daemon @@ -19,7 +11,7 @@ from plinth.modules.firewall.components import Firewall from plinth.package import Packages, install from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('BIND enables you to publish your Domain Name System (DNS) information ' @@ -32,32 +24,6 @@ _description = [ box_name=_(cfg.box_name)), ] -CONFIG_FILE = '/etc/bind/named.conf.options' -ZONES_DIR = '/var/bind/pri' - -DEFAULT_CONFIG = ''' -acl goodclients { - localnets; -}; -options { -directory "/var/cache/bind"; - -recursion yes; -allow-query { goodclients; }; - -forwarders { - -}; -forward first; - -dnssec-enable yes; -dnssec-validation auto; - -auth-nxdomain no; # conform to RFC1035 -listen-on-v6 { any; }; -}; -''' - class BindApp(app_module.App): """FreedomBox app for Bind.""" @@ -100,154 +66,10 @@ class BindApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('bind', - ['setup', '--old-version', - str(old_version)]) + privileged.setup(old_version) self.enable() def force_upgrade(self, _packages): """Force upgrade the managed packages to resolve conffile prompt.""" install(['bind9'], force_configuration='old') return True - - -def get_config(): - """Get current configuration""" - data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] - - forwarders = '' - dnssec_enabled = False - flag = False - for line in data: - if re.match(r'^\s*forwarders\s+{', line): - flag = True - elif re.match(r'^\s*dnssec-enable\s+yes;', line): - dnssec_enabled = True - elif flag and '//' not in line: - forwarders = re.sub('[;]', '', line) - flag = False - - conf = { - 'forwarders': forwarders, - 'enable_dnssec': dnssec_enabled, - } - return conf - - -def set_forwarders(forwarders): - """Set DNS forwarders.""" - flag = 0 - data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] - conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') - for line in data: - if re.match(r'^\s*forwarders\s+{', line): - conf_file.write(line + '\n') - for dns in forwarders.split(): - conf_file.write(dns + '; ') - conf_file.write('\n') - flag = 1 - elif '};' in line and flag == 1: - conf_file.write(line + '\n') - flag = 0 - elif flag == 0: - conf_file.write(line + '\n') - conf_file.close() - - -def set_dnssec(choice): - """Enable or disable DNSSEC.""" - data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] - - if choice == 'enable': - conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') - for line in data: - if re.match(r'//\s*dnssec-enable\s+yes;', line): - line = line.lstrip('/') - conf_file.write(line + '\n') - conf_file.close() - - if choice == 'disable': - conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') - for line in data: - if re.match(r'^\s*dnssec-enable\s+yes;', line): - line = '//' + line - conf_file.write(line + '\n') - conf_file.close() - - -def get_served_domains(): - """ - - Augeas path for zone files: - =========================== - augtool> print /files/var/bind/pri/local.zone - /files/var/bind/pri/local.zone - /files/var/bind/pri/local.zone/$TTL = "604800" - /files/var/bind/pri/local.zone/@[1] - /files/var/bind/pri/local.zone/@[1]/1 - /files/var/bind/pri/local.zone/@[1]/1/class = "IN" - /files/var/bind/pri/local.zone/@[1]/1/type = "SOA" - /files/var/bind/pri/local.zone/@[1]/1/mname = "localhost." - /files/var/bind/pri/local.zone/@[1]/1/rname = "root.localhost." - /files/var/bind/pri/local.zone/@[1]/1/serial = "2" - /files/var/bind/pri/local.zone/@[1]/1/refresh = "604800" - /files/var/bind/pri/local.zone/@[1]/1/retry = "86400" - /files/var/bind/pri/local.zone/@[1]/1/expiry = "2419200" - /files/var/bind/pri/local.zone/@[1]/1/minimum = "604800" - /files/var/bind/pri/local.zone/@[2] - /files/var/bind/pri/local.zone/@[2]/1 - /files/var/bind/pri/local.zone/@[2]/1/class = "IN" - /files/var/bind/pri/local.zone/@[2]/1/type = "NS" - /files/var/bind/pri/local.zone/@[2]/1/rdata = "localhost." - /files/var/bind/pri/local.zone/@[3] - /files/var/bind/pri/local.zone/@[3]/1 - /files/var/bind/pri/local.zone/@[3]/1/class = "IN" - /files/var/bind/pri/local.zone/@[3]/1/type = "A" - /files/var/bind/pri/local.zone/@[3]/1/rdata = "127.0.0.1" - /files/var/bind/pri/local.zone/@[4] - /files/var/bind/pri/local.zone/@[4]/1 - /files/var/bind/pri/local.zone/@[4]/1/class = "IN" - /files/var/bind/pri/local.zone/@[4]/1/type = "AAAA" - /files/var/bind/pri/local.zone/@[4]/1/rdata = "::1" - - Need to find the related functionality to parse the A records - - Retrieve from /etc/bind/db* zone files all the configured A records. - Assuming zones files in ZONES_DIR are all used. - :return: dictionary in the form 'domain_name': ['ip_address', 'ipv6_addr'] - """ - RECORD_TYPES = ('A', 'AAAA') - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - aug.set('/augeas/load/Dns_Zone/lens', 'Dns_Zone.lns') - - zone_file_path = Path(ZONES_DIR) - zone_files = [zf for zf in zone_file_path.iterdir() if zf.is_file()] - - # augeas load only required files - for zone_file in zone_files: - aug.set('/augeas/load/Dns_Zone/incl[last() + 1]', str(zone_file)) - - aug.load() - - served_domains = defaultdict(list) - for zone_file in zone_files: - base_path = '/files/%s/@[{record_order}]/1/{field}' % zone_file - count = 1 - mname = aug.get(base_path.format(record_order=count, field='mname')) - while True: - record_type = aug.get( - base_path.format(record_order=count, field='type')) - - # no record type ends the search - if record_type is None: - break - - if record_type in RECORD_TYPES: - served_domains[mname].append( - aug.get(base_path.format(record_order=count, - field='rdata'))) - - count += 1 - - return served_domains diff --git a/plinth/modules/bind/privileged.py b/plinth/modules/bind/privileged.py new file mode 100644 index 000000000..562ee5199 --- /dev/null +++ b/plinth/modules/bind/privileged.py @@ -0,0 +1,198 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configuration helper for BIND server.""" + +import re +from collections import defaultdict +from pathlib import Path + +import augeas + +from plinth import action_utils +from plinth.actions import privileged + +CONFIG_FILE = '/etc/bind/named.conf.options' +ZONES_DIR = '/var/bind/pri' + +DEFAULT_CONFIG = ''' +acl goodclients { + localnets; +}; +options { +directory "/var/cache/bind"; + +recursion yes; +allow-query { goodclients; }; + +forwarders { + +}; +forward first; + +dnssec-enable yes; +dnssec-validation auto; + +auth-nxdomain no; # conform to RFC1035 +listen-on-v6 { any; }; +}; +''' + + +@privileged +def setup(old_version: int): + """Setup BIND configuration.""" + if old_version == 0: + with open(CONFIG_FILE, 'w', encoding='utf-8') as conf_file: + conf_file.write(DEFAULT_CONFIG) + + Path(ZONES_DIR).mkdir(exist_ok=True, parents=True) + + action_utils.service_restart('named') + + +@privileged +def configure(forwarders: str, dnssec: bool): + """Configure BIND.""" + _set_forwarders(forwarders) + _set_dnssec(dnssec) + action_utils.service_restart('named') + + +def get_config(): + """Get current configuration.""" + data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] + + forwarders = '' + dnssec_enabled = False + flag = False + for line in data: + if re.match(r'^\s*forwarders\s+{', line): + flag = True + elif re.match(r'^\s*dnssec-enable\s+yes;', line): + dnssec_enabled = True + elif flag and '//' not in line: + forwarders = re.sub('[;]', '', line) + flag = False + + conf = { + 'forwarders': forwarders, + 'enable_dnssec': dnssec_enabled, + } + return conf + + +def _set_forwarders(forwarders): + """Set DNS forwarders.""" + flag = 0 + data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] + conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') + for line in data: + if re.match(r'^\s*forwarders\s+{', line): + conf_file.write(line + '\n') + for dns in forwarders.split(): + conf_file.write(dns + '; ') + conf_file.write('\n') + flag = 1 + elif '};' in line and flag == 1: + conf_file.write(line + '\n') + flag = 0 + elif flag == 0: + conf_file.write(line + '\n') + conf_file.close() + + +def _set_dnssec(choice): + """Enable or disable DNSSEC.""" + data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] + + if choice: + conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') + for line in data: + if re.match(r'//\s*dnssec-enable\s+yes;', line): + line = line.lstrip('/') + conf_file.write(line + '\n') + conf_file.close() + else: + conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') + for line in data: + if re.match(r'^\s*dnssec-enable\s+yes;', line): + line = '//' + line + conf_file.write(line + '\n') + conf_file.close() + + +def get_served_domains(): + """Return list of domains service handles. + + Augeas path for zone files: + =========================== + augtool> print /files/var/bind/pri/local.zone + /files/var/bind/pri/local.zone + /files/var/bind/pri/local.zone/$TTL = "604800" + /files/var/bind/pri/local.zone/@[1] + /files/var/bind/pri/local.zone/@[1]/1 + /files/var/bind/pri/local.zone/@[1]/1/class = "IN" + /files/var/bind/pri/local.zone/@[1]/1/type = "SOA" + /files/var/bind/pri/local.zone/@[1]/1/mname = "localhost." + /files/var/bind/pri/local.zone/@[1]/1/rname = "root.localhost." + /files/var/bind/pri/local.zone/@[1]/1/serial = "2" + /files/var/bind/pri/local.zone/@[1]/1/refresh = "604800" + /files/var/bind/pri/local.zone/@[1]/1/retry = "86400" + /files/var/bind/pri/local.zone/@[1]/1/expiry = "2419200" + /files/var/bind/pri/local.zone/@[1]/1/minimum = "604800" + /files/var/bind/pri/local.zone/@[2] + /files/var/bind/pri/local.zone/@[2]/1 + /files/var/bind/pri/local.zone/@[2]/1/class = "IN" + /files/var/bind/pri/local.zone/@[2]/1/type = "NS" + /files/var/bind/pri/local.zone/@[2]/1/rdata = "localhost." + /files/var/bind/pri/local.zone/@[3] + /files/var/bind/pri/local.zone/@[3]/1 + /files/var/bind/pri/local.zone/@[3]/1/class = "IN" + /files/var/bind/pri/local.zone/@[3]/1/type = "A" + /files/var/bind/pri/local.zone/@[3]/1/rdata = "127.0.0.1" + /files/var/bind/pri/local.zone/@[4] + /files/var/bind/pri/local.zone/@[4]/1 + /files/var/bind/pri/local.zone/@[4]/1/class = "IN" + /files/var/bind/pri/local.zone/@[4]/1/type = "AAAA" + /files/var/bind/pri/local.zone/@[4]/1/rdata = "::1" + + Need to find the related functionality to parse the A records + + Retrieve from /etc/bind/db* zone files all the configured A records. + Assuming zones files in ZONES_DIR are all used. + :return: dictionary in the form 'domain_name': ['ip_address', 'ipv6_addr'] + """ + RECORD_TYPES = ('A', 'AAAA') + aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + + augeas.Augeas.NO_MODL_AUTOLOAD) + aug.set('/augeas/load/Dns_Zone/lens', 'Dns_Zone.lns') + + zone_file_path = Path(ZONES_DIR) + zone_files = [zf for zf in zone_file_path.iterdir() if zf.is_file()] + + # augeas load only required files + for zone_file in zone_files: + aug.set('/augeas/load/Dns_Zone/incl[last() + 1]', str(zone_file)) + + aug.load() + + served_domains = defaultdict(list) + for zone_file in zone_files: + base_path = '/files/%s/@[{record_order}]/1/{field}' % zone_file + count = 1 + mname = aug.get(base_path.format(record_order=count, field='mname')) + while True: + record_type = aug.get( + base_path.format(record_order=count, field='type')) + + # no record type ends the search + if record_type is None: + break + + if record_type in RECORD_TYPES: + served_domains[mname].append( + aug.get(base_path.format(record_order=count, + field='rdata'))) + + count += 1 + + return served_domains diff --git a/plinth/modules/bind/tests/test_bind.py b/plinth/modules/bind/tests/test_bind.py index 94d8743bd..465fd3781 100644 --- a/plinth/modules/bind/tests/test_bind.py +++ b/plinth/modules/bind/tests/test_bind.py @@ -13,11 +13,11 @@ from plinth.modules import bind def fixture_configuration_file(tmp_path): """Setup the a bind configuration file temporary directory.""" conf_file = tmp_path / 'named.conf.options' - conf_file.write_text(bind.DEFAULT_CONFIG) - old_config_file = bind.CONFIG_FILE - bind.CONFIG_FILE = str(conf_file) + conf_file.write_text(bind.privileged.DEFAULT_CONFIG) + old_config_file = bind.privileged.CONFIG_FILE + bind.privileged.CONFIG_FILE = str(conf_file) yield - bind.CONFIG_FILE = old_config_file + bind.privileged.CONFIG_FILE = old_config_file @pytest.fixture @@ -40,51 +40,49 @@ $TTL 604800 @ IN AAAA {aaaa_record} """ # noqa - old_zones_dir = bind.ZONES_DIR - bind.ZONES_DIR = tmp_path - zones_dir_path = Path(bind.ZONES_DIR) + old_zones_dir = bind.privileged.ZONES_DIR + bind.privileged.ZONES_DIR = tmp_path + zones_dir_path = Path(bind.privileged.ZONES_DIR) zones_dir_path.mkdir(exist_ok=True, parents=True) local_path = zones_dir_path / "local.zone" local_path.write_text( test_zone_file.format(name='localhost.', a_record="127.0.0.1", - aaaa_record="::1") - ) + aaaa_record="::1")) custom_zone_path = zones_dir_path / "custom.zone" custom_zone_path.write_text( test_zone_file.format(name='custom.domain.', a_record="10.10.10.1", - aaaa_record="fe80::c6e9:84ff:fe16:95da") - ) + aaaa_record="fe80::c6e9:84ff:fe16:95da")) yield local_path.unlink() custom_zone_path.unlink() - bind.ZONES_DIR = old_zones_dir + bind.privileged.ZONES_DIR = old_zones_dir @pytest.mark.usefixtures('configuration_file') def test_set_forwarders(): """Test that setting forwarders works.""" - bind.set_forwarders('8.8.8.8 8.8.4.4') - conf = bind.get_config() + bind.privileged._set_forwarders('8.8.8.8 8.8.4.4') + conf = bind.privileged.get_config() assert conf['forwarders'] == '8.8.8.8 8.8.4.4' - bind.set_forwarders('') - conf = bind.get_config() + bind.privileged._set_forwarders('') + conf = bind.privileged.get_config() assert conf['forwarders'] == '' @pytest.mark.usefixtures('configuration_file') def test_enable_dnssec(): """Test that enabling DNSSEC works.""" - bind.set_dnssec('enable') - conf = bind.get_config() + bind.privileged._set_dnssec(True) + conf = bind.privileged.get_config() assert conf['enable_dnssec'] - bind.set_dnssec('disable') - conf = bind.get_config() + bind.privileged._set_dnssec(False) + conf = bind.privileged.get_config() assert not conf['enable_dnssec'] @@ -94,8 +92,9 @@ def test_get_correct_served_domains(): Test that get_served_domains collects the right a/aaaa records from zone files """ - served_domains = bind.get_served_domains() + served_domains = bind.privileged.get_served_domains() assert served_domains['localhost.'] == ["127.0.0.1", "::1"] assert served_domains['custom.domain.'] == [ - "10.10.10.1", "fe80::c6e9:84ff:fe16:95da"] + "10.10.10.1", "fe80::c6e9:84ff:fe16:95da" + ] diff --git a/plinth/modules/bind/views.py b/plinth/modules/bind/views.py index 4300eeddb..20ab92e85 100644 --- a/plinth/modules/bind/views.py +++ b/plinth/modules/bind/views.py @@ -1,33 +1,28 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for BIND module. -""" +"""Views for BIND module.""" from django.contrib import messages from django.utils.translation import gettext_lazy as _ -from plinth import actions -from plinth.modules import bind, names +from plinth.modules import names from plinth.views import AppView -from . import get_config +from . import privileged from .forms import BindForm class BindAppView(AppView): # pylint: disable=too-many-ancestors """A specialized view for configuring Bind.""" + app_id = 'bind' form_class = BindForm template_name = 'bind.html' def get_context_data(self, *args, **kwargs): - """ - Get/append information for domains bind is configured to respond for - and additional names from the names module - """ + """Get/append information for domains and additional names.""" context = super().get_context_data(**kwargs) - served_domains = bind.get_served_domains() + served_domains = privileged.get_served_domains() context['domains_table'] = [] for key, val in served_domains.items(): if key == 'localhost.': @@ -53,21 +48,17 @@ class BindAppView(AppView): # pylint: disable=too-many-ancestors def get_initial(self): """Return the values to fill in the form.""" initial = super().get_initial() - initial.update(get_config()) + initial.update(privileged.get_config()) return initial def form_valid(self, form): """Change the configurations of Bind service.""" data = form.cleaned_data - old_config = get_config() + old_config = privileged.get_config() if old_config['forwarders'] != data['forwarders'] \ or old_config['enable_dnssec'] != data['enable_dnssec']: - dnssec_setting = 'enable' if data['enable_dnssec'] else 'disable' - actions.superuser_run('bind', [ - 'configure', '--forwarders', data['forwarders'], '--dnssec', - dnssec_setting - ]) + privileged.configure(data['forwarders'], data['enable_dnssec']) messages.success(self.request, _('Configuration updated')) return super().form_valid(form) From d7a60b1acad9b34a2d7acc9bb977d136d5028c10 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 16:08:29 -0700 Subject: [PATCH 17/90] calibre: Use privileged decorator for actions Tests: - Unit and functional tests work. - Creating a library works. - An error while creating library shows as proper message. - Deleting a library works. - An error while deleting library shows as proper messages. - Creating/deleting library reflects properly in the list of libraries. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/calibre | 76 ------------------- plinth/modules/calibre/__init__.py | 24 +----- plinth/modules/calibre/forms.py | 8 +- plinth/modules/calibre/privileged.py | 47 ++++++++++++ plinth/modules/calibre/tests/test_actions.py | 67 ---------------- .../modules/calibre/tests/test_privileged.py | 64 ++++++++++++++++ plinth/modules/calibre/tests/test_views.py | 22 +++--- plinth/modules/calibre/views.py | 25 +++--- 8 files changed, 136 insertions(+), 197 deletions(-) delete mode 100755 actions/calibre create mode 100644 plinth/modules/calibre/privileged.py delete mode 100644 plinth/modules/calibre/tests/test_actions.py create mode 100644 plinth/modules/calibre/tests/test_privileged.py diff --git a/actions/calibre b/actions/calibre deleted file mode 100755 index bc8d51cd7..000000000 --- a/actions/calibre +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for calibre. -""" - -import argparse -import json -import pathlib -import shutil -import subprocess - -from plinth.modules import calibre - -LIBRARIES_PATH = pathlib.Path('/var/lib/calibre-server-freedombox/libraries') - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('list-libraries', - help='Return the list of libraries setup') - subparser = subparsers.add_parser('create-library', - help='Create an empty library') - subparser.add_argument('name', help='Name of the new library') - subparser = subparsers.add_parser('delete-library', - help='Delete a library and its contents') - subparser.add_argument('name', help='Name of the library to delete') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_list_libraries(_): - """Return the list of libraries setup.""" - libraries = [] - for library in LIBRARIES_PATH.glob('*/metadata.db'): - libraries.append(str(library.parent.name)) - - print(json.dumps({'libraries': libraries})) - - -def subcommand_create_library(arguments): - """Create an empty library.""" - calibre.validate_library_name(arguments.name) - library = LIBRARIES_PATH / arguments.name - library.mkdir(mode=0o755) # Raise exception if already exists - subprocess.call( - ['calibredb', '--with-library', library, 'list_categories'], - stdout=subprocess.DEVNULL) - - # Force systemd StateDirectory= logic to assign proper ownership to the - # DynamicUser= - shutil.chown(LIBRARIES_PATH.parent, 'root', 'root') - - -def subcommand_delete_library(arguments): - """Delete a library and its contents.""" - calibre.validate_library_name(arguments.name) - library = LIBRARIES_PATH / arguments.name - shutil.rmtree(library) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/calibre/__init__.py b/plinth/modules/calibre/__init__.py index 93aeb164d..9dc446f29 100644 --- a/plinth/modules/calibre/__init__.py +++ b/plinth/modules/calibre/__init__.py @@ -1,14 +1,10 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for calibre e-book library. -""" +"""FreedomBox app for calibre e-book library.""" -import json import re from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -109,21 +105,3 @@ def validate_library_name(library_name): """Raise exception if library name does not fit the accepted pattern.""" if not re.fullmatch(r'[A-Za-z0-9_.-]+', library_name): raise Exception('Invalid library name') - - -def list_libraries(): - """Return a list of libraries.""" - output = actions.superuser_run('calibre', ['list-libraries']) - return json.loads(output)['libraries'] - - -def create_library(name): - """Create an empty library.""" - actions.superuser_run('calibre', ['create-library', name]) - actions.superuser_run('service', ['try-restart', CalibreApp.DAEMON]) - - -def delete_library(name): - """Delete a library and its contents.""" - actions.superuser_run('calibre', ['delete-library', name]) - actions.superuser_run('service', ['try-restart', CalibreApp.DAEMON]) diff --git a/plinth/modules/calibre/forms.py b/plinth/modules/calibre/forms.py index 378c43420..085413277 100644 --- a/plinth/modules/calibre/forms.py +++ b/plinth/modules/calibre/forms.py @@ -1,14 +1,12 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Django form for configuring calibre. -""" +"""Django form for configuring calibre.""" from django import forms from django.core import validators from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ -from plinth.modules import calibre +from . import privileged class CreateLibraryForm(forms.Form): @@ -25,7 +23,7 @@ class CreateLibraryForm(forms.Form): """Check if the library name is valid.""" name = self.cleaned_data['name'] - if name in calibre.list_libraries(): + if name in privileged.list_libraries(): raise ValidationError( _('A library with this name already exists.')) diff --git a/plinth/modules/calibre/privileged.py b/plinth/modules/calibre/privileged.py new file mode 100644 index 000000000..88db062fc --- /dev/null +++ b/plinth/modules/calibre/privileged.py @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configuration helper for calibre.""" + +import pathlib +import shutil +import subprocess + +from plinth import action_utils +from plinth.actions import privileged +from plinth.modules import calibre + +LIBRARIES_PATH = pathlib.Path('/var/lib/calibre-server-freedombox/libraries') + + +@privileged +def list_libraries() -> list[str]: + """Return the list of libraries setup.""" + libraries = [] + for library in LIBRARIES_PATH.glob('*/metadata.db'): + libraries.append(str(library.parent.name)) + + return libraries + + +@privileged +def create_library(name: str): + """Create an empty library.""" + calibre.validate_library_name(name) + library = LIBRARIES_PATH / name + library.mkdir(mode=0o755) # Raise exception if already exists + subprocess.call( + ['calibredb', '--with-library', library, 'list_categories'], + stdout=subprocess.DEVNULL) + + # Force systemd StateDirectory= logic to assign proper ownership to the + # DynamicUser= + shutil.chown(LIBRARIES_PATH.parent, 'root', 'root') + action_utils.service_try_restart(calibre.CalibreApp.DAEMON) + + +@privileged +def delete_library(name: str): + """Delete a library and its contents.""" + calibre.validate_library_name(name) + library = LIBRARIES_PATH / name + shutil.rmtree(library) + action_utils.service_try_restart(calibre.CalibreApp.DAEMON) diff --git a/plinth/modules/calibre/tests/test_actions.py b/plinth/modules/calibre/tests/test_actions.py deleted file mode 100644 index 5708c011e..000000000 --- a/plinth/modules/calibre/tests/test_actions.py +++ /dev/null @@ -1,67 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Test module for calibre actions. -""" - -import json -import pathlib -from unittest.mock import call, patch - -import pytest - -actions_name = 'calibre' - - -@pytest.fixture(autouse=True) -def fixture_libraries_path(actions_module, tmpdir): - """Set the libraries path in the actions module.""" - actions_module.LIBRARIES_PATH = pathlib.Path(str(tmpdir)) - - -@pytest.fixture(autouse=True) -def fixture_patch(): - """Patch some underlying methods.""" - - def side_effect(*args, **_kwargs): - if args[0][0] != 'calibredb': - return - - path = pathlib.Path(args[0][2]) / 'metadata.db' - path.touch() - - with patch('subprocess.call') as subprocess_call, \ - patch('shutil.chown'): - subprocess_call.side_effect = side_effect - yield - - -def test_list_libraries(call_action): - """Test listing libraries.""" - assert json.loads(call_action(['list-libraries'])) == {'libraries': []} - call_action(['create-library', 'TestLibrary']) - expected_output = {'libraries': ['TestLibrary']} - assert json.loads(call_action(['list-libraries'])) == expected_output - - -@patch('shutil.chown') -def test_create_library(chown, call_action, actions_module): - """Test creating a library.""" - call_action(['create-library', 'TestLibrary']) - library = actions_module.LIBRARIES_PATH / 'TestLibrary' - assert (library / 'metadata.db').exists() - assert library.stat().st_mode == 0o40755 - expected_output = {'libraries': ['TestLibrary']} - assert json.loads(call_action(['list-libraries'])) == expected_output - - chown.assert_has_calls([call(library.parent.parent, 'root', 'root')]) - - -def test_delete_library(call_action): - """Test deleting a library.""" - call_action(['create-library', 'TestLibrary']) - - call_action(['delete-library', 'TestLibrary']) - assert json.loads(call_action(['list-libraries'])) == {'libraries': []} - - with pytest.raises(FileNotFoundError): - call_action(['delete-library', 'TestLibrary']) diff --git a/plinth/modules/calibre/tests/test_privileged.py b/plinth/modules/calibre/tests/test_privileged.py new file mode 100644 index 000000000..2b85f3eab --- /dev/null +++ b/plinth/modules/calibre/tests/test_privileged.py @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Test module for calibre actions.""" + +import pathlib +from unittest.mock import call, patch + +import pytest + +from plinth.modules.calibre import privileged + +pytestmark = pytest.mark.usefixtures('mock_privileged') +privileged_modules_to_mock = ['plinth.modules.calibre.privileged'] + + +@pytest.fixture(autouse=True) +def fixture_libraries_path(tmpdir): + """Set the libraries path in the actions module.""" + privileged.LIBRARIES_PATH = pathlib.Path(str(tmpdir)) + + +@pytest.fixture(autouse=True) +def fixture_patch(): + """Patch some underlying methods.""" + + def side_effect(*args, **_kwargs): + if args[0][0] != 'calibredb': + return + + path = pathlib.Path(args[0][2]) / 'metadata.db' + path.touch() + + with patch('subprocess.call') as subprocess_call, \ + patch('shutil.chown'): + subprocess_call.side_effect = side_effect + yield + + +def test_list_libraries(): + """Test listing libraries.""" + assert privileged.list_libraries() == [] + privileged.create_library('TestLibrary') + assert privileged.list_libraries() == ['TestLibrary'] + + +@patch('shutil.chown') +def test_create_library(chown): + """Test creating a library.""" + privileged.create_library('TestLibrary') + library = privileged.LIBRARIES_PATH / 'TestLibrary' + assert (library / 'metadata.db').exists() + assert library.stat().st_mode == 0o40755 + assert privileged.list_libraries() == ['TestLibrary'] + + chown.assert_has_calls([call(library.parent.parent, 'root', 'root')]) + + +def test_delete_library(): + """Test deleting a library.""" + privileged.create_library('TestLibrary') + privileged.delete_library('TestLibrary') + assert privileged.list_libraries() == [] + + with pytest.raises(FileNotFoundError): + privileged.delete_library('TestLibrary') diff --git a/plinth/modules/calibre/tests/test_views.py b/plinth/modules/calibre/tests/test_views.py index d1ee16747..c7076ac91 100644 --- a/plinth/modules/calibre/tests/test_views.py +++ b/plinth/modules/calibre/tests/test_views.py @@ -10,7 +10,7 @@ from django import urls from django.contrib.messages.storage.fallback import FallbackStorage from django.http.response import Http404 -from plinth import actions, module_loader +from plinth import module_loader from plinth.modules.calibre import views # For all tests, use plinth.urls instead of urls configured for testing @@ -30,7 +30,8 @@ def fixture_calibre_urls(): @pytest.fixture(autouse=True) def calibre_patch(): """Patch calibre methods.""" - with patch('plinth.modules.calibre.list_libraries') as list_libraries: + with patch('plinth.modules.calibre.privileged.list_libraries' + ) as list_libraries: list_libraries.return_value = ['TestExistingLibrary'] yield @@ -46,7 +47,7 @@ def make_request(request, view, **kwargs): return response, messages -@patch('plinth.modules.calibre.create_library') +@patch('plinth.modules.calibre.privileged.create_library') def test_create_library(create_library, rf): """Test that create library view works.""" form_data = {'calibre-name': 'TestLibrary'} @@ -60,11 +61,10 @@ def test_create_library(create_library, rf): create_library.assert_has_calls([call('TestLibrary')]) -@patch('plinth.modules.calibre.create_library') +@patch('plinth.modules.calibre.privileged.create_library') def test_create_library_failed(create_library, rf): """Test that create library fails as expected.""" - create_library.side_effect = actions.ActionError('calibre', 'TestOutput', - 'TestError') + create_library.side_effect = RuntimeError('TestError') form_data = {'calibre-name': 'TestLibrary'} request = rf.post(urls.reverse('calibre:create-library'), data=form_data) view = views.CreateLibraryView.as_view() @@ -109,7 +109,7 @@ def test_delete_library_confirmation_view(_app, rf): assert response.context_data['name'] == 'TestExistingLibrary' -@patch('plinth.modules.calibre.delete_library') +@patch('plinth.modules.calibre.privileged.delete_library') @patch('plinth.app.App.get') def test_delete_library(_app, delete_library, rf): """Test that deleting a library works.""" @@ -121,18 +121,16 @@ def test_delete_library(_app, delete_library, rf): delete_library.assert_has_calls([call('TestExistingLibrary')]) -@patch('plinth.modules.calibre.delete_library') +@patch('plinth.modules.calibre.privileged.delete_library') def test_delete_library_error(delete_library, rf): """Test that deleting a library shows error when operation fails.""" - delete_library.side_effect = actions.ActionError('calibre', 'TestInput', - 'TestError') + delete_library.side_effect = ValueError('TestError') response, messages = make_request(rf.post(''), views.delete_library, name='TestExistingLibrary') assert response.status_code == 302 assert response.url == urls.reverse('calibre:index') assert list(messages)[0].message == \ - 'Could not delete TestExistingLibrary: '\ - "('calibre', 'TestInput', 'TestError')" + 'Could not delete TestExistingLibrary: TestError' def test_delete_library_non_existing(rf): diff --git a/plinth/modules/calibre/views.py b/plinth/modules/calibre/views.py index d8a9e6e5b..3db0fbfb5 100644 --- a/plinth/modules/calibre/views.py +++ b/plinth/modules/calibre/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the calibre module. -""" +"""Views for the calibre module.""" from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin @@ -12,28 +10,28 @@ from django.urls import reverse_lazy from django.utils.translation import gettext as _ from django.views.generic.edit import FormView -from plinth import actions from plinth import app as app_module from plinth import views -from plinth.modules import calibre -from . import forms +from . import forms, privileged class CalibreAppView(views.AppView): """Serve configuration form.""" + app_id = 'calibre' template_name = 'calibre.html' def get_context_data(self, **kwargs): """Return additional context for rendering the template.""" context = super().get_context_data(**kwargs) - context['libraries'] = calibre.list_libraries() + context['libraries'] = privileged.list_libraries() return context class CreateLibraryView(SuccessMessageMixin, FormView): """View to create an empty library.""" + form_class = forms.CreateLibraryForm prefix = 'calibre' template_name = 'form.html' @@ -43,28 +41,27 @@ class CreateLibraryView(SuccessMessageMixin, FormView): def form_valid(self, form): """Create the library on valid form submission.""" try: - calibre.create_library(form.cleaned_data['name']) - except actions.ActionError as error: + privileged.create_library(form.cleaned_data['name']) + except Exception as error: self.success_message = '' - error_text = error.args[2].split('\n')[0] messages.error( self.request, "{0} {1}".format( _('An error occurred while creating the library.'), - error_text)) + str(error))) return super().form_valid(form) def delete_library(request, name): """View to delete a library.""" - if name not in calibre.list_libraries(): + if name not in privileged.list_libraries(): raise Http404 if request.method == 'POST': try: - calibre.delete_library(name) + privileged.delete_library(name) messages.success(request, _('{name} deleted.').format(name=name)) - except actions.ActionError as error: + except Exception as error: messages.error( request, _('Could not delete {name}: {error}').format( From b29182a0ebfe956f962198a0724f95caa61540c6 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 16 Sep 2022 10:50:21 -0700 Subject: [PATCH 18/90] config: Minor update to privileged method signature Tests: - Setting logging method works. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/config/privileged.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plinth/modules/config/privileged.py b/plinth/modules/config/privileged.py index 264f668ae..6316e75ac 100644 --- a/plinth/modules/config/privileged.py +++ b/plinth/modules/config/privileged.py @@ -34,7 +34,7 @@ def get_logging_mode() -> str: @privileged -def set_logging_mode(mode: str) -> None: +def set_logging_mode(mode: str): """Set the current logging mode.""" if mode not in ('volatile', 'persistent', 'none'): raise ValueError('Invalid mode') From 06b56399863e0f17a6d9ccd583d118f282c20e09 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 16:14:22 -0700 Subject: [PATCH 19/90] config: Use privileged decorator for actions Tests: - Initial setup succeeds - (not tested, functionality removed later) During initial setup, if /etc/apache2/conf-available/freedombox.conf has home page other than /plinth, it will be changed to /plinth. - Setting the home page to Apache default, plinth, or an app works. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/config | 80 ----------------------------- plinth/modules/config/__init__.py | 35 ++++--------- plinth/modules/config/privileged.py | 44 ++++++++++++++++ 3 files changed, 55 insertions(+), 104 deletions(-) delete mode 100755 actions/config diff --git a/actions/config b/actions/config deleted file mode 100755 index 31da406ee..000000000 --- a/actions/config +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/python3 -# -*- mode: python -*- -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for FreedomBox general configuration. -""" - -import argparse -import os - -import augeas - -from plinth import action_utils -from plinth.modules.config import (APACHE_HOMEPAGE_CONF_FILE_NAME, - FREEDOMBOX_APACHE_CONFIG) - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - set_home_page = subparsers.add_parser( - 'set-home-page', - help='Set the home page for this FreedomBox instance.') - set_home_page.add_argument('homepage', - help='path to the webserver home page') - - subparsers.add_parser('reset-home-page', - help='Reset the homepage of the Apache server.') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_set_home_page(arguments): - """Set the default app for this FreedomBox.""" - conf_file_path = os.path.join('/etc/apache2/conf-available', - APACHE_HOMEPAGE_CONF_FILE_NAME) - - redirect_rule = 'RedirectMatch "^/$" "{}"\n'.format(arguments.homepage) - - with open(conf_file_path, 'w', encoding='utf-8') as conf_file: - conf_file.write(redirect_rule) - - action_utils.webserver_enable('freedombox-apache-homepage') - - -def subcommand_reset_home_page(_): - """Sets the Apache web server's home page to the default - /plinth.""" - config_file = FREEDOMBOX_APACHE_CONFIG - default_path = 'plinth' - - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') - aug.set('/augeas/load/Httpd/incl[last() + 1]', config_file) - aug.load() - - aug.defvar('conf', '/files' + config_file) - - for match in aug.match('/files' + config_file + - '/directive["RedirectMatch"]'): - if aug.get(match + "/arg[1]") == '''"^/$"''': - aug.set(match + "/arg[2]", '"/{}"'.format(default_path)) - - aug.save() - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/config/__init__.py b/plinth/modules/config/__init__.py index 80d2adb9e..93cedeb84 100644 --- a/plinth/modules/config/__init__.py +++ b/plinth/modules/config/__init__.py @@ -1,15 +1,11 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for basic system configuration. -""" +"""FreedomBox app for basic system configuration.""" -import os import socket import augeas from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.daemon import RelatedDaemon @@ -26,12 +22,6 @@ _description = [ 'like hostname, domain name, webserver home page etc.') ] -APACHE_CONF_ENABLED_DIR = '/etc/apache2/conf-enabled' -APACHE_HOMEPAGE_CONF_FILE_NAME = 'freedombox-apache-homepage.conf' -APACHE_HOMEPAGE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, - APACHE_HOMEPAGE_CONF_FILE_NAME) -FREEDOMBOX_APACHE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, - 'freedombox.conf') ADVANCED_MODE_KEY = 'advanced_mode' @@ -103,19 +93,18 @@ class ConfigApp(app_module.App): def get_domainname(): - """Return the domainname""" + """Return the domainname.""" fqdn = socket.getfqdn() return '.'.join(fqdn.split('.')[1:]) def get_hostname(): - """Return the hostname""" + """Return the hostname.""" return socket.gethostname() def home_page_url2scid(url): - """Returns the shortcut ID of the given home page url.""" - + """Return the shortcut ID of the given home page url.""" if url in ('/plinth/', '/plinth', 'plinth'): return 'plinth' @@ -134,7 +123,7 @@ def home_page_url2scid(url): def _home_page_scid2url(shortcut_id): - """Returns the url for the given home page shortcut ID.""" + """Return the url for the given home page shortcut ID.""" if shortcut_id is None: url = None elif shortcut_id == 'plinth': @@ -178,23 +167,22 @@ def _get_home_page_url(conf_file): def get_home_page(): """Return the shortcut ID that is set as current home page.""" - CONF_FILE = APACHE_HOMEPAGE_CONFIG if os.path.exists( - APACHE_HOMEPAGE_CONFIG) else FREEDOMBOX_APACHE_CONFIG + CONF_FILE = privileged.APACHE_HOMEPAGE_CONFIG if os.path.exists( + privileged.APACHE_HOMEPAGE_CONFIG + ) else privileged.FREEDOMBOX_APACHE_CONFIG url = _get_home_page_url(CONF_FILE) return home_page_url2scid(url) def change_home_page(shortcut_id): - """Change the FreedomBox's default redirect to URL of the shortcut - specified. - """ + """Change the FreedomBox's default redirect to URL of a shortcut.""" url = _home_page_scid2url(shortcut_id) if url is None: url = '/plinth/' # fall back to default url if scid is unknown. # URL may be a reverse_lazy() proxy - actions.superuser_run('config', ['set-home-page', str(url)]) + privileged.set_home_page(str(url)) def get_advanced_mode(): @@ -211,12 +199,11 @@ def set_advanced_mode(advanced_mode): def _migrate_home_page_config(): """Move the home page configuration to an external file.""" - # Hold the current home page in a variable home_page = get_home_page() # Reset the home page to plinth in freedombox.conf - actions.superuser_run('config', ['reset-home-page']) + privileged.reset_home_page() # Write the home page setting into the new conf file # This step is run at the end because it reloads the Apache server diff --git a/plinth/modules/config/privileged.py b/plinth/modules/config/privileged.py index 6316e75ac..e2bf76869 100644 --- a/plinth/modules/config/privileged.py +++ b/plinth/modules/config/privileged.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later """Configure miscellaneous system settings.""" +import os import pathlib import augeas @@ -8,6 +9,13 @@ import augeas from plinth import action_utils from plinth.actions import privileged +APACHE_CONF_ENABLED_DIR = '/etc/apache2/conf-enabled' +APACHE_HOMEPAGE_CONF_FILE_NAME = 'freedombox-apache-homepage.conf' +APACHE_HOMEPAGE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, + APACHE_HOMEPAGE_CONF_FILE_NAME) +FREEDOMBOX_APACHE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, + 'freedombox.conf') + JOURNALD_FILE = pathlib.Path('/etc/systemd/journald.conf.d/50-freedombox.conf') @@ -56,3 +64,39 @@ def set_logging_mode(mode: str): # systemd-journald is socket activated, it may not be running and it does # not support reload. action_utils.service_try_restart('systemd-journald') + + +@privileged +def set_home_page(homepage: str): + """Set the default app for this FreedomBox.""" + conf_file_path = os.path.join('/etc/apache2/conf-available', + APACHE_HOMEPAGE_CONF_FILE_NAME) + + redirect_rule = 'RedirectMatch "^/$" "{}"\n'.format(homepage) + + with open(conf_file_path, 'w', encoding='utf-8') as conf_file: + conf_file.write(redirect_rule) + + action_utils.webserver_enable('freedombox-apache-homepage') + + +@privileged +def reset_home_page(): + """Set the Apache web server's home page to the default - /plinth.""" + config_file = FREEDOMBOX_APACHE_CONFIG + default_path = 'plinth' + + aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + + augeas.Augeas.NO_MODL_AUTOLOAD) + aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') + aug.set('/augeas/load/Httpd/incl[last() + 1]', config_file) + aug.load() + + aug.defvar('conf', '/files' + config_file) + + for match in aug.match('/files' + config_file + + '/directive["RedirectMatch"]'): + if aug.get(match + "/arg[1]") == '''"^/$"''': + aug.set(match + "/arg[2]", '"/{}"'.format(default_path)) + + aug.save() From 40bf6add755dcf06f4f17d790fdef93bd1ec5974 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 1 Sep 2022 14:22:05 -0700 Subject: [PATCH 20/90] config: Use privileged decorator for set-hostname action Tests: - Running flake8 as in .gitlab-ci.yml works. - Changes the hostname works and it is updated in /etc/hostname - Avahi daemon is restarted Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- .gitlab-ci.yml | 2 +- actions/hostname-change | 8 -------- plinth/modules/config/privileged.py | 10 ++++++++++ plinth/modules/config/views.py | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) delete mode 100755 actions/hostname-change diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fa0ee5529..e54e7fc1b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ code-quality: stage: test needs: [] script: - - python3 -m flake8 --exclude actions/domainname-change,actions/hostname-change,actions/networks container plinth actions/* + - python3 -m flake8 --exclude actions/domainname-change,actions/networks container plinth actions/* unit-tests: stage: test diff --git a/actions/hostname-change b/actions/hostname-change deleted file mode 100755 index c5bdee448..000000000 --- a/actions/hostname-change +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: AGPL-3.0-or-later - -hostname="$1" - -hostnamectl set-hostname --transient --static "$hostname" - -service avahi-daemon restart diff --git a/plinth/modules/config/privileged.py b/plinth/modules/config/privileged.py index e2bf76869..077a4a674 100644 --- a/plinth/modules/config/privileged.py +++ b/plinth/modules/config/privileged.py @@ -3,6 +3,7 @@ import os import pathlib +import subprocess import augeas @@ -19,6 +20,15 @@ FREEDOMBOX_APACHE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, JOURNALD_FILE = pathlib.Path('/etc/systemd/journald.conf.d/50-freedombox.conf') +@privileged +def set_hostname(hostname: str): + """Set system hostname using hostnamectl.""" + subprocess.run( + ['hostnamectl', 'set-hostname', '--transient', '--static', hostname], + check=True) + action_utils.service_restart('avahi-daemon') + + def load_augeas(): """Initialize Augeas.""" aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + diff --git a/plinth/modules/config/views.py b/plinth/modules/config/views.py index 1e5599022..97d8dc6d0 100644 --- a/plinth/modules/config/views.py +++ b/plinth/modules/config/views.py @@ -102,7 +102,7 @@ class ConfigAppView(views.AppView): def set_hostname(hostname): - """Sets machine hostname to hostname""" + """Set machine hostname and send signals before and after.""" old_hostname = config.get_hostname() domainname = config.get_domainname() @@ -114,7 +114,7 @@ def set_hostname(hostname): new_hostname=hostname) LOGGER.info('Changing hostname to - %s', hostname) - actions.superuser_run('hostname-change', [hostname]) + privileged.set_hostname(hostname) LOGGER.info('Setting domain name after hostname change - %s', domainname) actions.superuser_run('domainname-change', [domainname]) From b60717443465fb94649acb96ebdbabe06e4a1446 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 1 Sep 2022 22:07:43 -0700 Subject: [PATCH 21/90] config: Use privileged decorator for set domainname action Tests: - Running flake8 as in .gitlab-ci.yml works. - Setting the domain name again to update /etc/hosts file after hostname change works - Setting the domain name from the text box works. New domain name is read back and shown properly. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- .gitlab-ci.yml | 2 +- actions/domainname-change | 21 --------------------- plinth/modules/config/privileged.py | 27 +++++++++++++++++++++++++++ plinth/modules/config/views.py | 17 ++++++++--------- 4 files changed, 36 insertions(+), 31 deletions(-) delete mode 100755 actions/domainname-change diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e54e7fc1b..ed2d2aa2b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ code-quality: stage: test needs: [] script: - - python3 -m flake8 --exclude actions/domainname-change,actions/networks container plinth actions/* + - python3 -m flake8 --exclude actions/networks container plinth actions/* unit-tests: stage: test diff --git a/actions/domainname-change b/actions/domainname-change deleted file mode 100755 index ef058297d..000000000 --- a/actions/domainname-change +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: AGPL-3.0-or-later - -domainname="$1" -hostname=$(hostname) - -if [ -z "$domainname" ] ; then - if grep -q 127.0.1.1 /etc/hosts ; then - sed -i "s/127.0.1.1.*/127.0.1.1 $hostname/" /etc/hosts - else - sed -i "/127.0.0.1.*/a \ - 127.0.1.1 $hostname" /etc/hosts - fi -else - if grep -q 127.0.1.1 /etc/hosts ; then - sed -i "s/127.0.1.1.*/127.0.1.1 $hostname.$domainname $hostname/" /etc/hosts - else - sed -i "/127.0.0.1.*/a \ - 127.0.1.1 $hostname.$domainname $hostname" /etc/hosts - fi -fi diff --git a/plinth/modules/config/privileged.py b/plinth/modules/config/privileged.py index 077a4a674..8dd170975 100644 --- a/plinth/modules/config/privileged.py +++ b/plinth/modules/config/privileged.py @@ -4,6 +4,7 @@ import os import pathlib import subprocess +from typing import Optional import augeas @@ -29,6 +30,32 @@ def set_hostname(hostname: str): action_utils.service_restart('avahi-daemon') +@privileged +def set_domainname(domainname: Optional[str] = None): + """Set system domainname in /etc/hosts.""" + hostname = subprocess.check_output(['hostname']).decode().strip() + hosts_path = pathlib.Path('/etc/hosts') + if domainname: + insert_line = f'127.0.1.1 {hostname}.{domainname} {hostname}\n' + else: + insert_line = f'127.0.1.1 {hostname}\n' + + lines = hosts_path.read_text(encoding='utf-8').splitlines(keepends=True) + new_lines = [] + found = False + for line in lines: + if '127.0.1.1' in line: + new_lines.append(insert_line) + found = True + else: + new_lines.append(line) + + if not found: + new_lines.append(insert_line) + + hosts_path.write_text(''.join(new_lines), encoding='utf-8') + + def load_augeas(): """Initialize Augeas.""" aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + diff --git a/plinth/modules/config/views.py b/plinth/modules/config/views.py index 97d8dc6d0..3e5b6fd67 100644 --- a/plinth/modules/config/views.py +++ b/plinth/modules/config/views.py @@ -1,14 +1,12 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox views for basic system configuration. -""" +"""FreedomBox views for basic system configuration.""" import logging from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import actions, views +from plinth import views from plinth.modules import config from plinth.signals import (domain_added, domain_removed, post_hostname_change, pre_hostname_change) @@ -21,11 +19,12 @@ LOGGER = logging.getLogger(__name__) class ConfigAppView(views.AppView): """Serve configuration page.""" + form_class = ConfigurationForm app_id = 'config' def get_initial(self): - """Return the current status""" + """Return the current status.""" return { 'hostname': config.get_hostname(), 'domainname': config.get_domainname(), @@ -35,7 +34,7 @@ class ConfigAppView(views.AppView): } def form_valid(self, form): - """Apply the form changes""" + """Apply the form changes.""" old_status = form.initial new_status = form.cleaned_data @@ -117,7 +116,7 @@ def set_hostname(hostname): privileged.set_hostname(hostname) LOGGER.info('Setting domain name after hostname change - %s', domainname) - actions.superuser_run('domainname-change', [domainname]) + privileged.set_domainname(domainname) post_hostname_change.send_robust(sender='config', old_hostname=old_hostname, @@ -125,7 +124,7 @@ def set_hostname(hostname): def set_domainname(domainname, old_domainname): - """Sets machine domain name to domainname""" + """Set machine domain name to domainname.""" old_domainname = config.get_domainname() # Domain name is not case sensitive, but Let's Encrypt certificate @@ -133,7 +132,7 @@ def set_domainname(domainname, old_domainname): domainname = domainname.lower() LOGGER.info('Changing domain name to - %s', domainname) - actions.superuser_run('domainname-change', [domainname]) + privileged.set_domainname(domainname) # Update domain registered with Name Services module. if old_domainname: From 7ff050511cca4c6b16ed9c1295f7be8f07fa3c1a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Sat, 1 Oct 2022 14:17:16 -0700 Subject: [PATCH 22/90] config: Minor refactor Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/config/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plinth/modules/config/views.py b/plinth/modules/config/views.py index 3e5b6fd67..7a21b988a 100644 --- a/plinth/modules/config/views.py +++ b/plinth/modules/config/views.py @@ -97,7 +97,7 @@ class ConfigAppView(views.AppView): if is_changed: messages.success(self.request, _('Configuration updated')) - return super(views.AppView, self).form_valid(form) + return super().form_valid(form) def set_hostname(hostname): From 013caa28bcd3cbb7713a3631f2074b73b873ae0b Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 16:21:20 -0700 Subject: [PATCH 23/90] coturn: Use privileged decorator for actions Tests: - Initial setup of coturn succeeds - Configuration file is created and required configuration is set. - Coturn is restarted - Coturn configuration is shown on app page. - Changing the domain succeeds and coturn configuration reflects the new domain. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/coturn/__init__.py | 15 ++---- .../modules/coturn/privileged.py | 52 ++++--------------- plinth/modules/coturn/views.py | 5 +- 3 files changed, 18 insertions(+), 54 deletions(-) rename actions/coturn => plinth/modules/coturn/privileged.py (65%) mode change 100755 => 100644 diff --git a/plinth/modules/coturn/__init__.py b/plinth/modules/coturn/__init__.py index 71498f5e8..a3c424191 100644 --- a/plinth/modules/coturn/__init__.py +++ b/plinth/modules/coturn/__init__.py @@ -1,16 +1,12 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Coturn server. -""" +"""FreedomBox app to configure Coturn server.""" -import json import logging import pathlib from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import menu from plinth.daemon import Daemon @@ -23,7 +19,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('Coturn is a server to facilitate audio/video calls and conferences by ' @@ -109,7 +105,7 @@ class CoturnApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('coturn', ['setup']) + privileged.setup() if old_version == 0: self.enable() @@ -151,14 +147,13 @@ def get_domains(): def set_domain(domain): """Set the TLS domain by writing a file to data directory.""" if domain: - actions.superuser_run('coturn', ['set-domain', domain]) + privileged.set_domain(domain) notify_configuration_change() def get_config(): """Return the coturn server configuration.""" - output = actions.superuser_run('coturn', ['get-config']) - config = json.loads(output) + config = privileged.get_config() return TurnConfiguration(config['realm'], [], config['static_auth_secret']) diff --git a/actions/coturn b/plinth/modules/coturn/privileged.py old mode 100755 new mode 100644 similarity index 65% rename from actions/coturn rename to plinth/modules/coturn/privileged.py index 38a2e1719..14f75feb4 --- a/actions/coturn +++ b/plinth/modules/coturn/privileged.py @@ -1,11 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Coturn daemon. -""" +"""Configuration helper for Coturn daemon.""" -import argparse -import json import pathlib import random import shutil @@ -14,31 +9,18 @@ import string import augeas from plinth import action_utils +from plinth.actions import privileged CONFIG_FILE = pathlib.Path('/etc/coturn/freedombox.conf') -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Setup Coturn server') - subparsers.add_parser('get-config', - help='Return the current configuration') - subparser = subparsers.add_parser('set-domain', help='Set the TLS domain') - subparser.add_argument('domain_name', help='TLS domain name to set') - - subparsers.required = True - return parser.parse_args() - - def _key_path(key): """Return the augeas path for a key.""" return '/files' + str(CONFIG_FILE) + '/' + key -def subcommand_setup(_): +@privileged +def setup(): """Setup Coturn server.""" CONFIG_FILE.parent.mkdir(exist_ok=True) if not CONFIG_FILE.exists(): @@ -75,25 +57,26 @@ def subcommand_setup(_): action_utils.service_try_restart('coturn') -def subcommand_get_config(_): - """Return the current configuration in JSON format.""" +@privileged +def get_config() -> dict[str, str]: + """Return the current configuration.""" aug = augeas_load() config = { 'static_auth_secret': aug.get(_key_path('static-auth-secret')), 'realm': aug.get(_key_path('realm')), } - print(json.dumps(config)) + return config -def subcommand_set_domain(arguments): +@privileged +def set_domain(domain_name: str): """Set the TLS domain. This value is usually not stored. So, set realm value even though it is not needed to set realm for REST API based authentication. - """ aug = augeas_load() - aug.set(_key_path('realm'), arguments.domain_name) + aug.set(_key_path('realm'), domain_name) aug.save() @@ -106,16 +89,3 @@ def augeas_load(): aug.load() return aug - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/coturn/views.py b/plinth/modules/coturn/views.py index 25e6e46b7..383e7f150 100644 --- a/plinth/modules/coturn/views.py +++ b/plinth/modules/coturn/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for Coturn app. -""" +"""Views for Coturn app.""" from django.contrib import messages from django.utils.translation import gettext_lazy as _ @@ -15,6 +13,7 @@ from . import forms class CoturnAppView(views.AppView): """Serve configuration page.""" + app_id = 'coturn' template_name = 'coturn.html' form_class = forms.CoturnForm From f9fd1b142a2ce9bb1fe8fde39bd349061918d077 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Mon, 29 Aug 2022 11:18:18 -0700 Subject: [PATCH 24/90] datetime: Use privileged decorator for actions Tests: - Setting timezone shows: - In the interface and - timedatectl Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/timezone-change | 37 --------------------------- plinth/modules/datetime/privileged.py | 13 ++++++++++ plinth/modules/datetime/views.py | 12 ++++----- 3 files changed, 19 insertions(+), 43 deletions(-) delete mode 100755 actions/timezone-change create mode 100644 plinth/modules/datetime/privileged.py diff --git a/actions/timezone-change b/actions/timezone-change deleted file mode 100755 index 8ba152975..000000000 --- a/actions/timezone-change +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Set time zones with timedatectl (requires root permission). -""" - -import argparse -import subprocess -import sys - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - parser.add_argument( - 'timezone', help='Time zone to set; see "timedatectl list-timezones".') - return parser.parse_args() - - -def _set_timezone(arguments): - """Set time zone with timedatectl.""" - try: - command = ['timedatectl', 'set-timezone', arguments.timezone] - subprocess.run(command, stdout=subprocess.DEVNULL, check=True) - except subprocess.CalledProcessError as exception: - print('Error setting timezone:', exception, file=sys.stderr) - sys.exit(1) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - _set_timezone(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/datetime/privileged.py b/plinth/modules/datetime/privileged.py new file mode 100644 index 000000000..45790405e --- /dev/null +++ b/plinth/modules/datetime/privileged.py @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Set time zone with timedatectl.""" + +import subprocess + +from plinth.actions import privileged + + +@privileged +def set_timezone(timezone: str): + """Set time zone with timedatectl.""" + command = ['timedatectl', 'set-timezone', timezone] + subprocess.run(command, stdout=subprocess.DEVNULL, check=True) diff --git a/plinth/modules/datetime/views.py b/plinth/modules/datetime/views.py index d92848245..68c228e9e 100644 --- a/plinth/modules/datetime/views.py +++ b/plinth/modules/datetime/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring date and time. -""" +"""FreedomBox app for configuring date and time.""" import logging import pathlib @@ -9,9 +7,9 @@ import pathlib from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import actions from plinth.views import AppView +from . import privileged from .forms import DateTimeForm logger = logging.getLogger(__name__) @@ -19,10 +17,12 @@ logger = logging.getLogger(__name__) class DateTimeAppView(AppView): """Serve configuration page.""" + form_class = DateTimeForm app_id = 'datetime' def get_initial(self): + """Return the values to fill in the form.""" status = super().get_initial() status['time_zone'] = self.get_current_time_zone() return status @@ -35,14 +35,14 @@ class DateTimeAppView(AppView): return time_zone or 'none' def form_valid(self, form): + """Change the timezone.""" old_status = form.initial new_status = form.cleaned_data if old_status['time_zone'] != new_status['time_zone'] and \ new_status['time_zone'] != 'none': try: - actions.superuser_run('timezone-change', - [new_status['time_zone']]) + privileged.set_timezone(new_status['time_zone']) except Exception as exception: messages.error( self.request, From 884e0d69ef899a8211772dc9b85849fb7461c8c1 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 16:27:44 -0700 Subject: [PATCH 25/90] deluge: Use privileged decorator for actions Tests: - Functional tests succeed - Setup completes successfully - deluge-web service create successfully - systemd is reloaded - deluge-web is restarted - deluged is restarted - Updating download location sets it in core.conf - Deluge web interface reflects that - Correct location is shown after update Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/deluge/__init__.py | 9 +-- .../modules/deluge/privileged.py | 61 ++++--------------- plinth/modules/deluge/views.py | 21 +++---- 3 files changed, 21 insertions(+), 70 deletions(-) rename actions/deluge => plinth/modules/deluge/privileged.py (75%) mode change 100755 => 100644 diff --git a/plinth/modules/deluge/__init__.py b/plinth/modules/deluge/__init__.py index d6c65a743..bf4605fee 100644 --- a/plinth/modules/deluge/__init__.py +++ b/plinth/modules/deluge/__init__.py @@ -1,11 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure a Deluge web client. -""" +"""FreedomBox app to configure a Deluge web client.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.daemon import Daemon @@ -16,7 +13,7 @@ from plinth.modules.users import add_user_to_share_group from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages -from . import manifest +from . import manifest, privileged _description = [ _('Deluge is a BitTorrent client that features a Web UI.'), @@ -96,5 +93,5 @@ class DelugeApp(app_module.App): """Install and configure the app.""" super().setup(old_version) add_user_to_share_group(SYSTEM_USER) - actions.superuser_run('deluge', ['setup']) + privileged.setup() self.enable() diff --git a/actions/deluge b/plinth/modules/deluge/privileged.py old mode 100755 new mode 100644 similarity index 75% rename from actions/deluge rename to plinth/modules/deluge/privileged.py index e34437e2f..d507b5a56 --- a/actions/deluge +++ b/plinth/modules/deluge/privileged.py @@ -1,11 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for BitTorrent web client. -""" +"""Configuration helper for BitTorrent web client.""" -import argparse -import json import pathlib import subprocess import time @@ -13,6 +8,7 @@ import time import augeas from plinth import action_utils +from plinth.actions import privileged from plinth.modules.deluge.utils import Config DELUGED_DEFAULT_FILE = '/etc/default/deluged' @@ -53,27 +49,6 @@ WantedBy=multi-user.target ''' # noqa: E501 -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Setup deluge') - - subparsers.add_parser('get-configuration', - help='Return the current configuration') - - subparser = subparsers.add_parser('set-configuration', - help='Set the configuration parameter') - subparser.add_argument('parameter', - help='Name of the configuration parameter') - subparser.add_argument('value', - help='Value of the configuration parameter') - - subparsers.required = True - return parser.parse_args() - - def _set_configuration(filename, parameter, value): """Set the configuration parameter.""" deluged_is_running = action_utils.service_is_running('deluged') @@ -116,25 +91,24 @@ def _set_deluged_daemon_options(): aug.save() -def subcommand_get_configuration(_): - """Return the current deluged configuration in JSON format.""" +@privileged +def get_configuration() -> dict[str, str]: + """Return the current deluged configuration.""" with Config(DELUGE_CONF_DIR / 'core.conf') as config: download_location = config.content['download_location'] - print(json.dumps({'download_location': download_location})) + return {'download_location': download_location} -def subcommand_set_configuration(arguments): +@privileged +def set_configuration(download_location: str): """Set the deluged configuration.""" - if arguments.parameter != 'download_location': - return - - _set_configuration('core.conf', arguments.parameter, arguments.value) + _set_configuration('core.conf', 'download_location', download_location) -def subcommand_setup(_): +@privileged +def setup(): """Perform initial setup for deluge.""" - with open(DELUGE_WEB_SYSTEMD_SERVICE_PATH, 'w', encoding='utf-8') as file_handle: file_handle.write(DELUGE_WEB_SYSTEMD_SERVICE) @@ -180,16 +154,3 @@ def _wait_for_configuration(service, file_name): if not is_running: action_utils.service_stop(service) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/deluge/views.py b/plinth/modules/deluge/views.py index e97b5cd7d..d8f6edc8b 100644 --- a/plinth/modules/deluge/views.py +++ b/plinth/modules/deluge/views.py @@ -1,20 +1,18 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Django views for Deluge. -""" - -import json +"""Django views for Deluge.""" from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import actions, views +from plinth import views +from . import privileged from .forms import DelugeForm class DelugeAppView(views.AppView): """Serve configuration page.""" + diagnostics_module_name = 'deluge' form_class = DelugeForm app_id = 'deluge' @@ -22,8 +20,7 @@ class DelugeAppView(views.AppView): def get_initial(self): """Get current Deluge server settings.""" status = super().get_initial() - configuration = json.loads( - actions.superuser_run('deluge', ['get-configuration'])) + configuration = privileged.get_configuration() status['storage_path'] = configuration['download_location'] return status @@ -33,12 +30,8 @@ class DelugeAppView(views.AppView): new_status = form.cleaned_data if old_status['storage_path'] != new_status['storage_path']: - new_configuration = [ - 'download_location', new_status['storage_path'] - ] - - actions.superuser_run('deluge', - ['set-configuration'] + new_configuration) + privileged.set_configuration( + download_location=new_status['storage_path']) messages.success(self.request, _('Configuration updated')) return super().form_valid(form) From 79e48310a1348b9906f2f04789d4ea1e7f8cf533 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 2 Sep 2022 08:39:13 -0700 Subject: [PATCH 26/90] dynamicdns: Use privileged decorator for actions Tests: - Functional tests work. - Initial setup works. - Setting the setup version to 1 and running the service upgrades to version 2. During this, export_config() and clean() work successfully. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/dynamicdns | 162 +----------------------- plinth/modules/dynamicdns/__init__.py | 8 +- plinth/modules/dynamicdns/privileged.py | 113 +++++++++++++++++ 3 files changed, 122 insertions(+), 161 deletions(-) create mode 100644 plinth/modules/dynamicdns/privileged.py diff --git a/actions/dynamicdns b/actions/dynamicdns index 3cbe07793..9f035ea7c 100755 --- a/actions/dynamicdns +++ b/actions/dynamicdns @@ -1,159 +1,9 @@ #!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later +"""Legacy configuration helper for Dynamic DNS, kept for compatibility. + +Cron jobs in the earlier implementation used to call into this script with the +sub-commands 'update' and 'success'. This action script now allows for any +arbitrary sub-command to be called and does nothing. It can be removed after +the release of Debian 12 (bookworm). """ -Configuration helper for Dynamic DNS. -""" - -import argparse -import json -import pathlib -import urllib - -_conf_dir = pathlib.Path('/etc/ez-ipupdate/') -_active_config = _conf_dir / 'ez-ipupdate.conf' -_inactive_config = _conf_dir / 'ez-ipupdate.inactive' -_helper_config = _conf_dir / 'ez-ipupdate-plinth.cfg' -_cron_job = pathlib.Path('/etc/cron.d/ez-ipupdate') - - -def parse_arguments(): - """ Return parsed command line arguments as dictionary. """ - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('export-config', - help='Print configuration in JSON format') - subparsers.add_parser('clean', help='Remove all old configuration files') - - subparsers.add_parser('update', help='For backwards compatibility') - subparser = subparsers.add_parser('success', - help='For backwards compatibility') - subparser.add_argument('wan_ip_address') - - subparsers.required = True - return parser.parse_args() - - -def _read_configuration(path, separator='='): - """Read ez-ipupdate configuration.""" - config = {} - for line in path.read_text().splitlines(): - if line.startswith('#'): - continue - - parts = line.partition(separator) - if parts[1]: - config[parts[0].strip()] = parts[2].strip() - else: - config[parts[0].strip()] = True - - return config - - -def subcommand_export_config(_): - """Print the old ez-ipupdate configuration in JSON format.""" - input_config = {} - if _active_config.exists(): - input_config = _read_configuration(_active_config) - elif _inactive_config.exists(): - input_config = _read_configuration(_inactive_config) - - helper = {} - if _helper_config.exists(): - helper.update(_read_configuration(_helper_config, separator=' ')) - - def _clean(value): - value_map = {'enabled': True, 'disabled': False, '': None} - return value_map.get(value, value) - - domain = { - 'service_type': 'gnudip', - 'domain': input_config.get('host'), - 'server': input_config.get('server'), - 'username': input_config.get('user', '').split(':')[0] or None, - 'password': input_config.get('user', '').split(':')[-1] or None, - 'ip_lookup_url': helper.get('IPURL'), - 'update_url': _clean(helper.get('POSTURL')) or None, - 'use_http_basic_auth': _clean(helper.get('POSTAUTH')), - 'disable_ssl_cert_check': _clean(helper.get('POSTSSLIGNORE')), - 'use_ipv6': _clean(helper.get('POSTUSEIPV6')), - } - - if isinstance(domain['update_url'], bool): - # 'POSTURL ' is a line found in the configuration file - domain['update_url'] = None - - if not domain['server']: - domain['service_type'] = 'other' - update_url = domain['update_url'] - try: - server = urllib.parse.urlparse(update_url).netloc - service_types = { - 'dynupdate.noip.com': 'noip.com', - 'dynupdate.no-ip.com': 'noip.com', - 'freedns.afraid.org': 'freedns.afraid.org' - } - domain['service_type'] = service_types.get(server, 'other') - except ValueError: - pass - - # Old logic for 'enabling' the app is as follows: If behind NAT, add - # cronjob. If not behind NAT and type is update URL, add cronjob. If not - # behind NAT and type is GnuDIP, move inactive configuration to active - # configuration and start the ez-ipupdate daemon. - enabled = False - if _cron_job.exists() or (domain['service_type'] == 'gnudip' - and _active_config.exists()): - enabled = True - - output_config = {'enabled': enabled, 'domains': {}} - if domain['domain']: - output_config['domains'][domain['domain']] = domain - - print(json.dumps(output_config)) - - -def subcommand_clean(_): - """Remove all old configuration files.""" - last_update = _conf_dir / 'last-update' - status = _conf_dir / 'ez-ipupdate.status' - current_ip = _conf_dir / 'ez-ipupdate.currentIP' - - cleanup_files = [ - _active_config, _inactive_config, last_update, _helper_config, status, - current_ip - ] - for cleanup_file in cleanup_files: - try: - cleanup_file.rename(cleanup_file.with_suffix('.bak')) - except FileNotFoundError: - pass - - _cron_job.unlink(missing_ok=True) - - -def subcommand_update(_): - """Empty subcommand kept only for backwards compatibility. - - Drop after stable release. - """ - - -def subcommand_success(_): - """Empty subcommand kept only for backwards compatibility. - - Drop after stable release. - """ - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/dynamicdns/__init__.py b/plinth/modules/dynamicdns/__init__.py index 79688396f..a6904e0c5 100644 --- a/plinth/modules/dynamicdns/__init__.py +++ b/plinth/modules/dynamicdns/__init__.py @@ -11,7 +11,6 @@ import urllib from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, glib, kvstore, menu from plinth.modules.backups.components import BackupRestore @@ -20,7 +19,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.signals import domain_added, domain_removed from plinth.utils import format_lazy -from . import gnudip, manifest +from . import gnudip, manifest, privileged logger = logging.getLogger(__name__) @@ -103,8 +102,7 @@ class DynamicDNSApp(app_module.App): self.enable() if old_version == 1: - config = actions.superuser_run('dynamicdns', ['export-config']) - config = json.loads(config) + config = privileged.export_config() if config['enabled']: self.enable() else: @@ -112,7 +110,7 @@ class DynamicDNSApp(app_module.App): del config['enabled'] set_config(config) - actions.superuser_run('dynamicdns', ['clean']) + privileged.clean() def _query_external_address(domain): diff --git a/plinth/modules/dynamicdns/privileged.py b/plinth/modules/dynamicdns/privileged.py new file mode 100644 index 000000000..79d618a33 --- /dev/null +++ b/plinth/modules/dynamicdns/privileged.py @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configuration helper for Dynamic DNS.""" + +import pathlib +import urllib + +from plinth.actions import privileged + +_conf_dir = pathlib.Path('/etc/ez-ipupdate/') +_active_config = _conf_dir / 'ez-ipupdate.conf' +_inactive_config = _conf_dir / 'ez-ipupdate.inactive' +_helper_config = _conf_dir / 'ez-ipupdate-plinth.cfg' +_cron_job = pathlib.Path('/etc/cron.d/ez-ipupdate') + + +def _read_configuration(path, separator='='): + """Read ez-ipupdate configuration.""" + config = {} + for line in path.read_text().splitlines(): + if line.startswith('#'): + continue + + parts = line.partition(separator) + if parts[1]: + config[parts[0].strip()] = parts[2].strip() + else: + config[parts[0].strip()] = True + + return config + + +@privileged +def export_config() -> dict[str, object]: + """Return the old ez-ipupdate configuration in JSON format.""" + input_config = {} + if _active_config.exists(): + input_config = _read_configuration(_active_config) + elif _inactive_config.exists(): + input_config = _read_configuration(_inactive_config) + + helper = {} + if _helper_config.exists(): + helper.update(_read_configuration(_helper_config, separator=' ')) + + def _clean(value): + value_map = {'enabled': True, 'disabled': False, '': None} + return value_map.get(value, value) + + domain = { + 'service_type': 'gnudip', + 'domain': input_config.get('host'), + 'server': input_config.get('server'), + 'username': input_config.get('user', '').split(':')[0] or None, + 'password': input_config.get('user', '').split(':')[-1] or None, + 'ip_lookup_url': helper.get('IPURL'), + 'update_url': _clean(helper.get('POSTURL')) or None, + 'use_http_basic_auth': _clean(helper.get('POSTAUTH')), + 'disable_ssl_cert_check': _clean(helper.get('POSTSSLIGNORE')), + 'use_ipv6': _clean(helper.get('POSTUSEIPV6')), + } + + if isinstance(domain['update_url'], bool): + # 'POSTURL ' is a line found in the configuration file + domain['update_url'] = None + + if not domain['server']: + domain['service_type'] = 'other' + update_url = domain['update_url'] + try: + server = urllib.parse.urlparse(update_url).netloc + service_types = { + 'dynupdate.noip.com': 'noip.com', + 'dynupdate.no-ip.com': 'noip.com', + 'freedns.afraid.org': 'freedns.afraid.org' + } + domain['service_type'] = service_types.get(server, 'other') + except ValueError: + pass + + # Old logic for 'enabling' the app is as follows: If behind NAT, add + # cronjob. If not behind NAT and type is update URL, add cronjob. If not + # behind NAT and type is GnuDIP, move inactive configuration to active + # configuration and start the ez-ipupdate daemon. + enabled = False + if _cron_job.exists() or (domain['service_type'] == 'gnudip' + and _active_config.exists()): + enabled = True + + output_config = {'enabled': enabled, 'domains': {}} + if domain['domain']: + output_config['domains'][domain['domain']] = domain + + return output_config + + +@privileged +def clean(): + """Remove all old configuration files.""" + last_update = _conf_dir / 'last-update' + status = _conf_dir / 'ez-ipupdate.status' + current_ip = _conf_dir / 'ez-ipupdate.currentIP' + + cleanup_files = [ + _active_config, _inactive_config, last_update, _helper_config, status, + current_ip + ] + for cleanup_file in cleanup_files: + try: + cleanup_file.rename(cleanup_file.with_suffix('.bak')) + except FileNotFoundError: + pass + + _cron_job.unlink(missing_ok=True) From a579c648fd8b0f89264c47487b43beff3ae595b6 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 1 Sep 2022 14:13:02 -0700 Subject: [PATCH 27/90] ejabberd: Use privileged decorator for actions Tests: - Functional tests work (backup test intermittent failure) - Initial setup works - Domain name is configured properly - FAIL: Changing hostname works (See #2276) - Adding a domain to the system works - Current list of domains shown properly in app page - Setting list of domains works - Showing TURN configuration works - Updating TURN configuration in coturn page works - Enabling/disabling MAM status works - Configure file is updated - App page shows correct status Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/ejabberd/__init__.py | 53 ++-- .../modules/ejabberd/privileged.py | 240 +++++------------- .../ejabberd/tests/test_turn_config.py | 37 ++- plinth/modules/ejabberd/views.py | 20 +- 4 files changed, 109 insertions(+), 241 deletions(-) rename actions/ejabberd => plinth/modules/ejabberd/privileged.py (58%) mode change 100755 => 100644 diff --git a/plinth/modules/ejabberd/__init__.py b/plinth/modules/ejabberd/__init__.py index 1e768b019..22276b5de 100644 --- a/plinth/modules/ejabberd/__init__.py +++ b/plinth/modules/ejabberd/__init__.py @@ -1,15 +1,13 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure ejabberd server. -""" +"""FreedomBox app to configure ejabberd server.""" import json import logging +from typing import Tuple from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -25,7 +23,7 @@ from plinth.signals import (domain_added, post_hostname_change, pre_hostname_change) from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('XMPP is an open and standardized communication protocol. Here ' @@ -131,14 +129,12 @@ class EjabberdApp(app_module.App): domainname = config.get_domainname() logger.info('ejabberd service domainname - %s', domainname) - actions.superuser_run('ejabberd', - ['pre-install', '--domainname', domainname]) + privileged.pre_install(domainname) # XXX: Configure all other domain names super().setup(old_version) self.get_component('letsencrypt-ejabberd').setup_certificates( [domainname]) - actions.superuser_run('ejabberd', - ['setup', '--domainname', domainname]) + privileged.setup(domainname) self.enable() # Configure STUN/TURN only if there's a valid TLS domain set for Coturn @@ -155,19 +151,14 @@ class EjabberdTurnConsumer(TurnConsumer): def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs): - """ - Backup ejabberd database before hostname is changed. - """ + """Backup ejabberd database before hostname is changed.""" del sender # Unused del kwargs # Unused app = app_module.App.get('ejabberd') if app.needs_setup(): return - actions.superuser_run('ejabberd', [ - 'pre-change-hostname', '--old-hostname', old_hostname, - '--new-hostname', new_hostname - ]) + privileged.pre_change_hostname(old_hostname, new_hostname) def on_post_hostname_change(sender, old_hostname, new_hostname, **kwargs): @@ -178,21 +169,16 @@ def on_post_hostname_change(sender, old_hostname, new_hostname, **kwargs): if app.needs_setup(): return - actions.superuser_run('ejabberd', [ - 'change-hostname', '--old-hostname', old_hostname, '--new-hostname', - new_hostname - ], run_in_background=True) + privileged.change_hostname(_run_in_background=True) def get_domains(): - """Return the list of domains configured for ejabberd. - """ + """Return the list of domains configured for ejabberd.""" app = app_module.App.get('ejabberd') if app.needs_setup(): return [] - output = actions.superuser_run('ejabberd', ['get-domains']) - return json.loads(output) + return privileged.get_domains() def on_domain_added(sender, domain_type, name='', description='', @@ -204,7 +190,7 @@ def on_domain_added(sender, domain_type, name='', description='', domains = get_domains() if name not in domains: - actions.superuser_run('ejabberd', ['add-domain', '--domainname', name]) + privileged.add_domain(name) app.get_component('letsencrypt-ejabberd').setup_certificates() @@ -214,9 +200,7 @@ def set_domains(domains): if not domains or app.needs_setup(): return - commands = ['set-domains', '--domains'] - commands.extend(domains) - actions.superuser_run('ejabberd', commands) + privileged.set_domains(domains) app.get_component('letsencrypt-ejabberd').setup_certificates() @@ -227,14 +211,11 @@ def update_turn_configuration(config: TurnConfiguration, managed=True, if not force and app.needs_setup(): return - params = ['configure-turn'] - params += ['--managed'] if managed else [] - actions.superuser_run('ejabberd', params, input=config.to_json().encode()) + privileged.configure_turn(json.loads(config.to_json()), managed) -def get_turn_configuration() -> (TurnConfiguration, bool): +def get_turn_configuration() -> Tuple[TurnConfiguration, bool]: """Get the latest STUN/TURN configuration.""" - json_config = actions.superuser_run('ejabberd', ['get-turn-config']) - tc, managed = json.loads(json_config) - return (TurnConfiguration(tc['domain'], tc['uris'], - tc['shared_secret']), managed) + tc, managed = privileged.get_turn_config() + return TurnConfiguration(tc['domain'], tc['uris'], + tc['shared_secret']), managed diff --git a/actions/ejabberd b/plinth/modules/ejabberd/privileged.py old mode 100755 new mode 100644 similarity index 58% rename from actions/ejabberd rename to plinth/modules/ejabberd/privileged.py index 42de818f5..4e6037d1f --- a/actions/ejabberd +++ b/plinth/modules/ejabberd/privileged.py @@ -1,24 +1,23 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for the ejabberd service -""" +"""Configuration helper for the ejabberd service.""" -import argparse -import json +import logging import os import re import shutil import socket import subprocess -import sys from pathlib import Path +from typing import Any, Optional, Tuple from ruamel.yaml import YAML, scalarstring from plinth import action_utils +from plinth.actions import privileged from plinth.version import Version +logger = logging.getLogger(__name__) + EJABBERD_CONFIG = '/etc/ejabberd/ejabberd.yml' EJABBERD_BACKUP = '/var/log/ejabberd/ejabberd.dump' EJABBERD_BACKUP_NEW = '/var/log/ejabberd/ejabberd_new.dump' @@ -34,88 +33,9 @@ yaml.preserve_quotes = True TURN_URI_REGEX = r'(stun|turn):(.*):([0-9]{4})\?transport=(tcp|udp)' -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - # Get configuration - subparsers.add_parser('get-configuration', - help='Return the current configuration') - - # Preseed debconf values before packages are installed. - pre_install = subparsers.add_parser( - 'pre-install', - help='Preseed debconf values before packages are installed.') - pre_install.add_argument( - '--domainname', - help='The domain name that will be used by the XMPP service.') - - # Setup ejabberd configuration - setup = subparsers.add_parser('setup', help='Setup ejabberd configuration') - setup.add_argument( - '--domainname', - help='The domain name that will be used by the XMPP service.') - - # Prepare ejabberd for hostname change - pre_hostname_change = subparsers.add_parser( - 'pre-change-hostname', help='Prepare ejabberd for nodename change') - pre_hostname_change.add_argument('--old-hostname', - help='Previous hostname') - pre_hostname_change.add_argument('--new-hostname', help='New hostname') - - # Update ejabberd nodename - hostname_change = subparsers.add_parser('change-hostname', - help='Update ejabberd nodename') - hostname_change.add_argument('--old-hostname', help='Previous hostname') - hostname_change.add_argument('--new-hostname', help='New hostname') - - # Manage domain names - subparsers.add_parser('get-domains', - help='Get all configured domains in JSON format') - - add_domain = subparsers.add_parser('add-domain', - help='Add a domain name to ejabberd') - add_domain.add_argument('--domainname', help='New domain name') - - set_domains = subparsers.add_parser('set-domains', - help='Set list of ejabberd domains') - set_domains.add_argument('--domains', nargs='+', - help='One or more domain names') - - # Configure STUN/TURN server for use with ejabberd - turn = subparsers.add_parser( - 'configure-turn', help='Configure a TURN server for use with ejabberd') - turn.add_argument( - '--managed', required=False, default=False, action='store_true', - help='Whether configuration is provided by user or auto-managed by ' - 'FreedomBox') - - subparsers.add_parser( - 'get-turn-config', - help='Get the latest STUN/TURN configuration in JSON format') - - # Switch/check Message Archive Management (MAM) in ejabberd config - help_MAM = 'Switch or check Message Archive Management (MAM).' - mam = subparsers.add_parser('mam', help=help_MAM) - mam.add_argument('command', choices=('enable', 'disable', 'status'), - help=help_MAM) - - subparsers.required = True - return parser.parse_args() - - -def subcommand_get_configuration(_): - """Return the current configuration, specifically domains configured.""" - with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: - conf = yaml.load(file_handle) - - print(json.dumps({'domains': conf['hosts']})) - - -def subcommand_pre_install(arguments): +@privileged +def pre_install(domainname: str): """Preseed debconf values before packages are installed.""" - domainname = arguments.domainname if not domainname: # If new domainname is blank, use hostname instead. domainname = socket.gethostname() @@ -124,8 +44,9 @@ def subcommand_pre_install(arguments): ['ejabberd ejabberd/hostname string ' + domainname]) -def subcommand_setup(arguments): - """Enabled LDAP authentication""" +@privileged +def setup(domainname: str): + """Enable LDAP authentication.""" with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: conf = yaml.load(file_handle) @@ -143,19 +64,20 @@ def subcommand_setup(arguments): with open(EJABBERD_CONFIG, 'w', encoding='utf-8') as file_handle: yaml.dump(conf, file_handle) - upgrade_config(arguments.domainname) + _upgrade_config(domainname) try: subprocess.check_output(['ejabberdctl', 'restart']) except subprocess.CalledProcessError as err: - print('Failed to restart ejabberd with new configuration: %s', err) + logger.warn('Failed to restart ejabberd with new configuration: %s', + err) -def upgrade_config(domain): - """Fix the config file by removing deprecated settings""" +def _upgrade_config(domain): + """Fix the config file by removing deprecated settings.""" current_version = _get_version() if not current_version: - print('Warning: Unable to get ejabberd version.') + logger.warn('Warning: Unable to get ejabberd version.') with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: conf = yaml.load(file_handle) @@ -194,31 +116,25 @@ def upgrade_config(domain): yaml.dump(conf, file_handle) -def subcommand_pre_change_hostname(arguments): - """Prepare ejabberd for hostname change""" +@privileged +def pre_change_hostname(old_hostname: str, new_hostname: str): + """Prepare ejabberd for hostname change.""" if not shutil.which('ejabberdctl'): - print('ejabberdctl not found. Is ejabberd installed?') + logger.info('ejabberdctl not found') return - old_hostname = arguments.old_hostname - new_hostname = arguments.new_hostname - subprocess.call(['ejabberdctl', 'backup', EJABBERD_BACKUP]) - try: - subprocess.check_output([ - 'ejabberdctl', 'mnesia-change-nodename', - 'ejabberd@' + old_hostname, 'ejabberd@' + new_hostname, - EJABBERD_BACKUP, EJABBERD_BACKUP_NEW - ]) - os.remove(EJABBERD_BACKUP) - except subprocess.CalledProcessError as err: - print('Failed to change hostname in ejabberd backup database: %s', err) + subprocess.check_output([ + 'ejabberdctl', 'mnesia-change-nodename', 'ejabberd@' + old_hostname, + 'ejabberd@' + new_hostname, EJABBERD_BACKUP, EJABBERD_BACKUP_NEW + ]) + os.remove(EJABBERD_BACKUP) -def subcommand_change_hostname(arguments): - """Update ejabberd with new hostname""" +@privileged +def change_hostname(): + """Update ejabberd with new hostname.""" if not shutil.which('ejabberdctl'): - print('ejabberdctl not found. Is ejabberd installed?') return action_utils.service_stop('ejabberd') @@ -238,35 +154,34 @@ def subcommand_change_hostname(arguments): ['ejabberdctl', 'restore', EJABBERD_BACKUP_NEW]) os.remove(EJABBERD_BACKUP_NEW) except subprocess.CalledProcessError as err: - print('Failed to restore ejabberd backup database: %s', err) + logger.error('Failed to restore ejabberd backup database: %s', err) else: - print('Could not load ejabberd backup database: %s not found' % - EJABBERD_BACKUP_NEW) + logger.error('Could not load ejabberd backup database: %s not found' % + EJABBERD_BACKUP_NEW) -def subcommand_get_domains(_): +@privileged +def get_domains() -> list[str]: """Get all configured domains.""" if not shutil.which('ejabberdctl'): - print('ejabberdctl not found. Is ejabberd installed?') - return + return [] with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: conf = yaml.load(file_handle) - print(json.dumps(conf['hosts'])) + return conf['hosts'] -def subcommand_add_domain(arguments): +@privileged +def add_domain(domainname: str): """Update ejabberd with new domainname. Restarting ejabberd is handled by letsencrypt-ejabberd component. """ if not shutil.which('ejabberdctl'): - print('ejabberdctl not found. Is ejabberd installed?') + logger.info('ejabberdctl not found') return - domainname = arguments.domainname - # Add updated domainname to ejabberd hosts list. with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: conf = yaml.load(file_handle) @@ -281,43 +196,43 @@ def subcommand_add_domain(arguments): # Restarting ejabberd is handled by letsencrypt-ejabberd component. -def subcommand_set_domains(arguments): +@privileged +def set_domains(domains: list[str]): """Set list of ejabberd domains. Restarting ejabberd is handled by letsencrypt-ejabberd component. """ + if not len(domains): + raise ValueError('No domains provided') + if not shutil.which('ejabberdctl'): - print('ejabberdctl not found. Is ejabberd installed?') return with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: conf = yaml.load(file_handle) - conf['hosts'] = arguments.domains + conf['hosts'] = domains with open(EJABBERD_CONFIG, 'w', encoding='utf-8') as file_handle: yaml.dump(conf, file_handle) -def subcommand_mam(argument): +@privileged +def mam(command: str) -> Optional[bool]: """Enable, disable, or get status of Message Archive Management (MAM).""" + if command not in ('enable', 'disable', 'status'): + raise ValueError('Invalid command') with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: conf = yaml.load(file_handle) if 'modules' not in conf: - print('Found no "modules" entry in ejabberd configuration file.') - return + return None - if argument.command == 'status': - if 'mod_mam' in conf['modules']: - print('enabled') - return - else: - print('disabled') - return + if command == 'status': + return 'mod_mam' in conf['modules'] - if argument.command == 'enable': + if command == 'enable': # Explicitly set the recommended / default settings for mod_mam, # see https://docs.ejabberd.im/admin/configuration/#mod-mam. settings_mod_mam = { @@ -332,13 +247,10 @@ def subcommand_mam(argument): } } conf['modules'].update(settings_mod_mam) - elif argument.command == 'disable': + elif command == 'disable': # disable modules by erasing from config file if 'mod_mam' in conf['modules']: conf['modules'].pop('mod_mam') - else: - print("Unknown command: %s" % argument.command) - return with open(EJABBERD_CONFIG, 'w', encoding='utf-8') as file_handle: yaml.dump(conf, file_handle) @@ -346,6 +258,8 @@ def subcommand_mam(argument): if action_utils.service_is_running('ejabberd'): subprocess.call(['ejabberdctl', 'reload_config']) + return None + def _generate_service(uri: str) -> dict: """Generate ejabberd mod_stun_disco service config from Coturn URI.""" @@ -368,7 +282,8 @@ def _generate_uris(services: list[dict]) -> list[str]: ] -def subcommand_get_turn_config(_): +@privileged +def get_turn_config() -> Tuple[dict[str, Any], bool]: """Get the latest STUN/TURN configuration in JSON format.""" with open(EJABBERD_CONFIG, 'r', encoding='utf-8') as file_handle: conf = yaml.load(file_handle) @@ -377,24 +292,18 @@ def subcommand_get_turn_config(_): managed = os.path.exists(EJABBERD_MANAGED_COTURN) if bool(mod_stun_disco_config): - print( - json.dumps([{ - 'domain': '', - 'uris': _generate_uris(mod_stun_disco_config['services']), - 'shared_secret': mod_stun_disco_config['secret'], - }, managed])) + return { + 'domain': '', + 'uris': _generate_uris(mod_stun_disco_config['services']), + 'shared_secret': mod_stun_disco_config['secret'], + }, managed else: - print( - json.dumps([{ - 'domain': None, - 'uris': [], - 'shared_secret': None - }, managed])) + return {'domain': None, 'uris': [], 'shared_secret': None}, managed -def subcommand_configure_turn(arguments): +@privileged +def configure_turn(turn_server_config: dict[str, Any], managed: bool): """Set parameters for the STUN/TURN server to use with ejabberd.""" - turn_server_config = json.loads(''.join(sys.stdin)) uris = turn_server_config['uris'] mod_stun_disco_config = {} @@ -413,7 +322,7 @@ def subcommand_configure_turn(arguments): with open(EJABBERD_CONFIG, 'w', encoding='utf-8') as file_handle: yaml.dump(conf, file_handle) - if arguments.managed: + if managed: Path(EJABBERD_MANAGED_COTURN).touch() else: Path(EJABBERD_MANAGED_COTURN).unlink(missing_ok=True) @@ -423,7 +332,7 @@ def subcommand_configure_turn(arguments): def _get_version(): - """ Get the current ejabberd version """ + """Get the current ejabberd version.""" try: output = subprocess.check_output(['ejabberdctl', 'status']).decode('utf-8') @@ -435,16 +344,3 @@ def _get_version(): version = str(version_info[1]) return Version(version) return None - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/ejabberd/tests/test_turn_config.py b/plinth/modules/ejabberd/tests/test_turn_config.py index 055a01db5..564418a5e 100644 --- a/plinth/modules/ejabberd/tests/test_turn_config.py +++ b/plinth/modules/ejabberd/tests/test_turn_config.py @@ -11,6 +11,7 @@ import pytest from plinth.modules import ejabberd from plinth.modules.coturn.components import TurnConfiguration +from plinth.modules.ejabberd import privileged managed_configuration = TurnConfiguration( 'freedombox.local', [], @@ -20,9 +21,9 @@ overridden_configuration = TurnConfiguration( 'public.coturn.site', [], 'BUeKvKzhAsTZ8MEwMd3yTwpr2uvbOxgWe51aiP02OAGyOlj6WGuCyqj7iaOsbkC7') -actions_name = 'ejabberd' - +pytestmark = pytest.mark.usefixtures('mock_privileged') current_directory = pathlib.Path(__file__).parent +privileged_modules_to_mock = ['plinth.modules.ejabberd.privileged'] @pytest.fixture(name='conf_file') @@ -45,31 +46,27 @@ def fixture_managed_file(tmp_path): @pytest.fixture(autouse=True) -def fixture_set_configuration_paths(actions_module, conf_file, managed_file): +def fixture_set_configuration_paths(conf_file, managed_file): """Setup configuration file paths in action module.""" - actions_module.EJABBERD_CONFIG = conf_file - actions_module.EJABBERD_MANAGED_COTURN = managed_file + privileged.EJABBERD_CONFIG = conf_file + privileged.EJABBERD_MANAGED_COTURN = managed_file @pytest.fixture(name='test_configuration', autouse=True) -def fixture_test_configuration(call_action, conf_file): +def fixture_test_configuration(conf_file): """Use a separate ejabberd configuration for tests. - Patches actions.superuser_run with the fixture call_action. The module state is patched to be 'up-to-date'. """ - with patch('plinth.actions.superuser_run', - call_action), patch('plinth.app.App.get') as app_get: + with patch('plinth.app.App.get') as app_get: app = Mock() app_get.return_value = app app.needs_setup.return_value = False yield -def _set_turn_configuration(monkeypatch, config=managed_configuration, - managed=True): - monkeypatch.setattr('sys.stdin', config.to_json()) - with patch('plinth.action_utils.service_is_running', return_value=False): +def _set_turn_configuration(config=managed_configuration, managed=True): + with patch('plinth.privileged.service.is_running', return_value=False): ejabberd.update_turn_configuration(config, managed=managed) @@ -81,17 +78,17 @@ def _assert_conf(expected_configuration, expected_managed): assert managed == expected_managed -def test_managed_turn_server_configuration(monkeypatch): - _set_turn_configuration(monkeypatch) +def test_managed_turn_server_configuration(): + _set_turn_configuration() _assert_conf(managed_configuration, True) -def test_overridden_turn_server_configuration(monkeypatch): - _set_turn_configuration(monkeypatch, overridden_configuration, False) +def test_overridden_turn_server_configuration(): + _set_turn_configuration(overridden_configuration, False) _assert_conf(overridden_configuration, False) -def test_remove_turn_configuration(monkeypatch): - _set_turn_configuration(monkeypatch) - _set_turn_configuration(monkeypatch, TurnConfiguration(), False) +def test_remove_turn_configuration(): + _set_turn_configuration() + _set_turn_configuration(TurnConfiguration(), False) _assert_conf(TurnConfiguration(), False) diff --git a/plinth/modules/ejabberd/views.py b/plinth/modules/ejabberd/views.py index cca1b102b..eb01d2b1f 100644 --- a/plinth/modules/ejabberd/views.py +++ b/plinth/modules/ejabberd/views.py @@ -1,31 +1,30 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the Ejabberd module -""" +"""Views for the Ejabberd app.""" from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import actions from plinth.modules import coturn, ejabberd from plinth.modules.coturn.components import TurnConfiguration from plinth.views import AppView +from . import privileged from .forms import EjabberdForm class EjabberdAppView(AppView): """Show ejabberd as a service.""" + app_id = 'ejabberd' template_name = 'ejabberd.html' form_class = EjabberdForm def get_initial(self): - """Initial data to fill in the form.""" + """Return initial data to fill in the form.""" config, managed = ejabberd.get_turn_configuration() return super().get_initial() | { 'domain_names': ejabberd.get_domains(), - 'MAM_enabled': self.is_MAM_enabled(), + 'MAM_enabled': privileged.mam('status'), 'enable_managed_turn': managed, 'turn_uris': '\n'.join(config.uris), 'shared_secret': config.shared_secret @@ -65,9 +64,9 @@ class EjabberdAppView(AppView): def _handle_MAM_configuration(old_config, new_config): # note ejabberd action "enable" or "disable" restarts, if running if new_config['MAM_enabled']: - actions.superuser_run('ejabberd', ['mam', 'enable']) + privileged.mam('enable') else: - actions.superuser_run('ejabberd', ['mam', 'disable']) + privileged.mam('disable') def form_valid(self, form): """Enable/disable a service and set messages.""" @@ -96,8 +95,3 @@ class EjabberdAppView(AppView): messages.success(self.request, _('Configuration updated')) return super().form_valid(form) - - def is_MAM_enabled(self): - """Return whether Message Archive Management (MAM) is enabled.""" - output = actions.superuser_run('ejabberd', ['mam', 'status']) - return output.strip() == 'enabled' From 5389303e982dd6249897b6240a5df5e24426e33a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 2 Sep 2022 11:19:21 -0700 Subject: [PATCH 28/90] email: Use privileged decorator for actions Tests: - Functional tests work (uninstall test does not work) - Initial setup works - Domains are setup - Home is setup (others don't have permission for /var/mail) - Aliases configuration is setup - Postfix is setup - rspamd is setup - Changing primary domain works - Adding/removing domains works - Error during operations is handle properly: getting dkim key - Setting up DKIM key when changing, adding/removing domain works - Showing DKIM key in app page works Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/email | 66 --------------------- plinth/modules/email/__init__.py | 20 +++---- plinth/modules/email/aliases.py | 8 +-- plinth/modules/email/dns.py | 7 +-- plinth/modules/email/privileged/__init__.py | 18 +++--- plinth/modules/email/privileged/aliases.py | 9 +-- plinth/modules/email/privileged/dkim.py | 20 +++---- plinth/modules/email/privileged/domain.py | 17 +++--- plinth/modules/email/privileged/home.py | 13 ++-- plinth/modules/email/privileged/postfix.py | 20 +++---- plinth/modules/email/privileged/spam.py | 10 +--- plinth/modules/email/views.py | 2 +- 12 files changed, 63 insertions(+), 147 deletions(-) delete mode 100755 actions/email diff --git a/actions/email b/actions/email deleted file mode 100755 index 28704472b..000000000 --- a/actions/email +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for email server. -""" - -import argparse -import logging -import os -import sys - -import plinth.log -from plinth.modules.email import privileged - -EXIT_SYNTAX = 10 -EXIT_PERM = 20 - -logger = logging.getLogger(__file__) - - -def main(): - """Parse arguments.""" - plinth.log.action_init() - - parser = argparse.ArgumentParser() - parser.add_argument('module', help='Module to trigger action in') - parser.add_argument('action', help='Action to trigger in module') - parser.add_argument('arguments', help='String arguments for action', - nargs='*') - args = parser.parse_args() - - try: - _call(args.module, args.action, args.arguments) - except Exception as exception: - logger.exception(exception) - sys.exit(1) - - -def _call(module_name, action_name, arguments): - """Import the module and run action as superuser.""" - if os.getuid() != 0: - logger.critical('This action is reserved for root') - sys.exit(EXIT_PERM) - - # We only run actions defined in the privileged module - if module_name not in privileged.__all__: - logger.critical('Bad module name: %r', module_name) - sys.exit(EXIT_SYNTAX) - - module = getattr(privileged, module_name) - try: - action = getattr(module, 'action_' + action_name) - except AttributeError: - logger.critical('Bad action: %s/%r', module_name, action_name) - sys.exit(EXIT_SYNTAX) - - for argument in arguments: - if not isinstance(argument, str): - logger.critical('Bad argument: %s', argument) - sys.exit(EXIT_SYNTAX) - - action(*arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/email/__init__.py b/plinth/modules/email/__init__.py index 2f9236af0..76cb5fa3b 100644 --- a/plinth/modules/email/__init__.py +++ b/plinth/modules/email/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to manage an email server. -""" +"""FreedomBox app to manage an email server.""" import logging @@ -49,12 +47,13 @@ logger = logging.getLogger(__name__) class EmailApp(plinth.app.App): """FreedomBox app for an email server.""" + app_id = 'email' _version = 1 def __init__(self): - """The app's constructor""" + """Initialize the email app.""" super().__init__() info = plinth.app.Info(app_id=self.app_id, version=self._version, @@ -180,13 +179,14 @@ class EmailApp(plinth.app.App): super().setup(old_version) # Setup - privileged.home.setup() + privileged.setup_home() self.get_component('letsencrypt-email-postfix').setup_certificates() self.get_component('letsencrypt-email-dovecot').setup_certificates() - privileged.domain.set_domains() - privileged.postfix.setup() + privileged.domain.set_all_domains() + aliases.first_setup() + privileged.setup_postfix() aliases.setup_common_aliases(_get_first_admin()) - privileged.spam.setup() + privileged.setup_spam() # Restart daemons actions.superuser_run('service', ['try-restart', 'postfix']) @@ -218,7 +218,7 @@ def on_domain_added(sender, domain_type, name, description='', services=None, if app.needs_setup(): return - privileged.domain.set_domains() + privileged.domain.set_all_domains() def on_domain_removed(sender, domain_type, name='', **kwargs): @@ -227,4 +227,4 @@ def on_domain_removed(sender, domain_type, name='', **kwargs): if app.needs_setup(): return - privileged.domain.set_domains() + privileged.domain.set_all_domains() diff --git a/plinth/modules/email/aliases.py b/plinth/modules/email/aliases.py index 5d5b3fec8..425f63bd9 100644 --- a/plinth/modules/email/aliases.py +++ b/plinth/modules/email/aliases.py @@ -1,14 +1,12 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Manage email aliases stored in sqlite database. -""" +"""Manage email aliases stored in sqlite database.""" import contextlib import pwd import sqlite3 from dataclasses import dataclass -from plinth import actions +from . import privileged @dataclass @@ -75,7 +73,7 @@ def delete(username, aliases): def first_setup(): """Create the database file and schema inside it.""" - actions.superuser_run('email', ['aliases', 'setup']) + privileged.aliases.setup_aliases() # Create schema if not exists query = ''' diff --git a/plinth/modules/email/dns.py b/plinth/modules/email/dns.py index c6df85abe..fecd051b7 100644 --- a/plinth/modules/email/dns.py +++ b/plinth/modules/email/dns.py @@ -12,12 +12,11 @@ See: https://rspamd.com/doc/modules/dkim_signing.html from dataclasses import dataclass from typing import Union -from plinth.errors import ActionError - @dataclass class Entry: # pylint: disable=too-many-instance-attributes """A DNS entry.""" + type_: str value: str domain: Union[str, None] = None @@ -55,12 +54,12 @@ def get_entries(): f'rua=mailto:postmaster@{domain}; ') ] try: - dkim_public_key = privileged.dkim.get_public_key(domain) + dkim_public_key = privileged.get_dkim_public_key(domain) dkim_entries = [ Entry(domain='dkim._domainkey', type_='TXT', value=f'v=DKIM1; k=rsa; p={dkim_public_key}') ] - except ActionError: + except Exception: dkim_entries = [] autoconfig_entries = [ diff --git a/plinth/modules/email/privileged/__init__.py b/plinth/modules/email/privileged/__init__.py index 999f6efc0..cf5e8ea28 100644 --- a/plinth/modules/email/privileged/__init__.py +++ b/plinth/modules/email/privileged/__init__.py @@ -1,10 +1,14 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Provides privileged actions that run as root. -""" +"""Provides privileged actions that run as root.""" -from . import aliases, dkim, domain, home, postfix, spam, tls +from .aliases import setup_aliases +from .dkim import get_dkim_public_key, setup_dkim +from .domain import set_domains +from .home import setup_home +from .postfix import setup_postfix +from .spam import setup_spam -__all__ = ['aliases', 'domain', 'dkim', 'home', 'postfix', 'spam', 'tls'] - -from .aliases import action_setup +__all__ = [ + 'setup_aliases', 'get_dkim_public_key', 'setup_dkim', 'set_domains', + 'setup_home', 'setup_postfix', 'setup_spam' +] diff --git a/plinth/modules/email/privileged/aliases.py b/plinth/modules/email/privileged/aliases.py index 78e4ea62b..208a622b9 100644 --- a/plinth/modules/email/privileged/aliases.py +++ b/plinth/modules/email/privileged/aliases.py @@ -1,13 +1,14 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Privileged operations for managing aliases. -""" +"""Privileged operations for managing aliases.""" import pathlib import shutil +from plinth.actions import privileged -def action_setup(): + +@privileged +def setup_aliases(): """Create a the sqlite3 database to be managed by FreedomBox.""" path = pathlib.Path('/var/lib/postfix/freedombox-aliases/') path.mkdir(mode=0o750, exist_ok=True) diff --git a/plinth/modules/email/privileged/dkim.py b/plinth/modules/email/privileged/dkim.py index 95a413e8e..f57ba47fb 100644 --- a/plinth/modules/email/privileged/dkim.py +++ b/plinth/modules/email/privileged/dkim.py @@ -1,6 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Generate DKIM keys for signing outgoing messages. +"""Generate DKIM keys for signing outgoing messages. See: https://rspamd.com/doc/modules/dkim_signing.html """ @@ -10,7 +9,7 @@ import re import shutil import subprocess -from plinth import actions +from plinth.actions import privileged _keys_dir = pathlib.Path('/var/lib/rspamd/dkim/') @@ -23,24 +22,19 @@ def _validate_domain_name(domain): raise ValueError('Invalid domain name') -def get_public_key(domain): - """Return the DKIM public key for the given domain.""" - output = actions.superuser_run('email', - ['dkim', 'get_dkim_public_key', domain]) - return output.strip() - - -def action_get_dkim_public_key(domain): +@privileged +def get_dkim_public_key(domain: str) -> str: """Privileged action to get the public key from DKIM key.""" _validate_domain_name(domain) key_file = _keys_dir / f'{domain}.dkim.key' output = subprocess.check_output( ['openssl', 'rsa', '-in', str(key_file), '-pubout'], stderr=subprocess.DEVNULL) - print(''.join(output.decode().splitlines()[1:-1])) + return ''.join(output.decode().splitlines()[1:-1]) -def action_setup_dkim(domain): +@privileged +def setup_dkim(domain: str): """Create DKIM key for a given domain.""" _validate_domain_name(domain) diff --git a/plinth/modules/email/privileged/domain.py b/plinth/modules/email/privileged/domain.py index 10176933c..d8a792956 100644 --- a/plinth/modules/email/privileged/domain.py +++ b/plinth/modules/email/privileged/domain.py @@ -10,13 +10,13 @@ See: http://www.postfix.org/postconf.5.html#myhostname import pathlib import re -from plinth.actions import superuser_run +from plinth.actions import privileged from plinth.app import App from plinth.modules import config from plinth.modules.email import postfix from plinth.modules.names.components import DomainName -from . import tls +from . import dkim, tls def get_domains(): @@ -28,7 +28,7 @@ def get_domains(): return {'primary_domain': conf['mydomain'], 'all_domains': domains} -def set_domains(primary_domain=None): +def set_all_domains(primary_domain=None): """Set the primary domain and all the domains for postfix.""" all_domains = DomainName.list_names() if not primary_domain: @@ -37,10 +37,8 @@ def set_domains(primary_domain=None): primary_domain = config.get_domainname() or list(all_domains)[0] # Update configuration and don't restart daemons - superuser_run( - 'email', - ['domain', 'set_domains', primary_domain, ','.join(all_domains)]) - superuser_run('email', ['dkim', 'setup_dkim', primary_domain]) + set_domains(primary_domain, list(all_domains)) + dkim.setup_dkim(primary_domain) # Copy certificates (self-signed if needed) and restart daemons app = App.get('email') @@ -48,9 +46,10 @@ def set_domains(primary_domain=None): app.get_component('letsencrypt-email-dovecot').setup_certificates() -def action_set_domains(primary_domain, all_domains): +@privileged +def set_domains(primary_domain: str, all_domains: list[str]): """Set the primary domain and all the domains for postfix.""" - all_domains = [_clean_domain(domain) for domain in all_domains.split(',')] + all_domains = [_clean_domain(domain) for domain in all_domains] primary_domain = _clean_domain(primary_domain) defaults = {'$myhostname', 'localhost.$mydomain', 'localhost'} diff --git a/plinth/modules/email/privileged/home.py b/plinth/modules/email/privileged/home.py index 37d9ff2b4..544643dc3 100644 --- a/plinth/modules/email/privileged/home.py +++ b/plinth/modules/email/privileged/home.py @@ -8,20 +8,15 @@ https://doc.dovecot.org/configuration_manual/authentication/user_databases_userd import subprocess -from plinth import actions +from plinth.actions import privileged -def setup(): +@privileged +def setup_home(): """Set correct permissions on /var/mail/ directory. For each user, /var/mail/<user> is the 'dovecot mail home' for that user. Dovecot creates new directories with the same permissions as the parent - directory. Ensure that 'others' can access /var/mail/. - + directory. Ensure that 'others' can't access /var/mail/. """ - actions.superuser_run('email', ['home', 'setup']) - - -def action_setup(): - """Run chmod on /var/mail to remove all permissions for 'others'.""" subprocess.run(['chmod', 'o-rwx', '/var/mail'], check=True) diff --git a/plinth/modules/email/privileged/postfix.py b/plinth/modules/email/privileged/postfix.py index 9b42d6a50..be479c440 100644 --- a/plinth/modules/email/privileged/postfix.py +++ b/plinth/modules/email/privileged/postfix.py @@ -1,7 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configure postfix to use auth and local delivery with dovecot. Start smtps and -submission services. Setup aliases database. +"""Configure postix. + +- Configure postfix to use auth and local delivery with dovecot. +- Start SMTPS and submission services. Setup aliases database. See: https://doc.dovecot.org/configuration_manual/howto/postfix_and_dovecot_sasl/ @@ -9,9 +10,8 @@ See: https://doc.dovecot.org/configuration_manual/howto/postfix_dovecot_lmtp/ See: http://www.postfix.org/TLS_README.html """ -from plinth import actions +from plinth.actions import privileged -from .. import aliases from .. import postfix as postconf default_config = { @@ -57,13 +57,9 @@ smtps_service = postconf.Service(service='smtps', type_='inet', private='n', SQLITE_ALIASES = 'sqlite:/etc/postfix/freedombox-aliases.cf' -def setup(): - """Set SASL, mail submission, and user lookup settings.""" - aliases.first_setup() - actions.superuser_run('email', ['postfix', 'setup']) - - -def action_setup(): +@privileged +def setup_postfix(): + """Configure postfix.""" postconf.set_config(default_config) _setup_submission() _setup_alias_maps() diff --git a/plinth/modules/email/privileged/spam.py b/plinth/modules/email/privileged/spam.py index a2f8bbc8d..046a2b508 100644 --- a/plinth/modules/email/privileged/spam.py +++ b/plinth/modules/email/privileged/spam.py @@ -10,7 +10,7 @@ import pathlib import re import subprocess -from plinth import actions +from plinth.actions import privileged from plinth.modules.email import postfix _milter_config = { @@ -19,12 +19,8 @@ _milter_config = { } -def setup(): - """Trigger a privileged setup action.""" - actions.superuser_run('email', ['spam', 'setup']) - - -def action_setup(): +@privileged +def setup_spam(): """Compile sieve filters and set rspamd/postfix configuration.""" _compile_sieve() _setup_rspamd() diff --git a/plinth/modules/email/views.py b/plinth/modules/email/views.py index 70d8b4dd2..bac67c3b2 100644 --- a/plinth/modules/email/views.py +++ b/plinth/modules/email/views.py @@ -41,7 +41,7 @@ class EmailAppView(AppView): new_data = form.cleaned_data if old_data['primary_domain'] != new_data['primary_domain']: try: - privileged.domain.set_domains(new_data['primary_domain']) + privileged.domain.set_all_domains(new_data['primary_domain']) messages.success(self.request, _('Configuration updated')) except Exception: messages.error(self.request, From a62b7c752261d6378607d4cd9e842fddfefe365b Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 16:37:42 -0700 Subject: [PATCH 29/90] firewall: Use privileged decorator, drop showing running status - If a daemon is not-running, we already show an error message to the user. Use that mechanism instead of the custom one. Tests: - Functional tests work. - Initial setup for firewall on first boot works. - Default zone of the firewalld is set to external in /etc/firewalld.conf - Status of various apps is shown properly in the app page - If firewalld is not running, the app page is still displayed properly and message that firewalld is not running is shown. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/firewall/__init__.py | 36 +---- .../modules/firewall/privileged.py | 48 +----- .../modules/firewall/templates/firewall.html | 149 ++++++++---------- plinth/modules/firewall/views.py | 23 +-- 4 files changed, 88 insertions(+), 168 deletions(-) rename actions/firewall => plinth/modules/firewall/privileged.py (66%) mode change 100755 => 100644 diff --git a/plinth/modules/firewall/__init__.py b/plinth/modules/firewall/__init__.py index 8b4dc11f2..9603b8f06 100644 --- a/plinth/modules/firewall/__init__.py +++ b/plinth/modules/firewall/__init__.py @@ -1,14 +1,11 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure a firewall. -""" +"""FreedomBox app to configure a firewall.""" import contextlib import logging from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import Daemon @@ -16,7 +13,7 @@ from plinth.modules.backups.components import BackupRestore from plinth.package import Packages, install from plinth.utils import Version, format_lazy, import_from_gi -from . import manifest +from . import manifest, privileged gio = import_from_gi('Gio', '2.0') glib = import_from_gi('GLib', '2.0') @@ -98,7 +95,7 @@ class FirewallApp(app_module.App): def _run_setup(): """Run firewalld setup.""" - _run(['setup'], superuser=True) + privileged.setup() add_service('http', 'external') add_service('http', 'internal') add_service('https', 'external') @@ -171,17 +168,8 @@ def try_with_reload(operation): operation() -def get_enabled_status(): - """Return whether firewall is enabled""" - output = _run(['get-status'], superuser=True) - if not output: - return False - else: - return output.split()[0] == 'running' - - def get_enabled_services(zone): - """Return the status of various services currently enabled""" + """Return the status of various services currently enabled.""" with ignore_dbus_error(dbus_error='ServiceUnknown'): zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE) return zone_proxy.getServices('(s)', zone) @@ -190,7 +178,7 @@ def get_enabled_services(zone): def get_port_details(service_port): - """Return the port types and numbers for a service port""" + """Return the port types and numbers for a service port.""" try: return _port_details[service_port] except KeyError: @@ -215,7 +203,7 @@ def get_interfaces(zone): def add_service(port, zone): - """Enable a service in firewall""" + """Enable a service in firewall.""" with ignore_dbus_error(dbus_error='ServiceUnknown'): zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE) with ignore_dbus_error(service_error='ALREADY_ENABLED'): @@ -229,7 +217,7 @@ def add_service(port, zone): def remove_service(port, zone): - """Remove a service in firewall""" + """Remove a service in firewall.""" with ignore_dbus_error(dbus_error='ServiceUnknown'): zone_proxy = _get_dbus_proxy(_FIREWALLD_OBJECT, _ZONE_INTERFACE) with ignore_dbus_error(service_error='NOT_ENABLED'): @@ -240,13 +228,3 @@ def remove_service(port, zone): config_zone = _get_dbus_proxy(zone_path, _CONFIG_ZONE_INTERFACE) with ignore_dbus_error(service_error='NOT_ENABLED'): config_zone.removeService('(s)', port) - - -def _run(arguments, superuser=False): - """Run an given command and raise exception if there was an error""" - command = 'firewall' - - if superuser: - return actions.superuser_run(command, arguments) - else: - return actions.run(command, arguments) diff --git a/actions/firewall b/plinth/modules/firewall/privileged.py old mode 100755 new mode 100644 similarity index 66% rename from actions/firewall rename to plinth/modules/firewall/privileged.py index 68263087c..56592cdc1 --- a/actions/firewall +++ b/plinth/modules/firewall/privileged.py @@ -1,31 +1,12 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for FreedomBox firewall interface. -""" +"""Configuration helper for FreedomBox firewall interface.""" -import argparse import subprocess import augeas from plinth import action_utils - - -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - # Setup - subparsers.add_parser('setup', help='Perform basic firewall setup') - - # Get status - subparsers.add_parser('get-status', - help='Get whether firewalld is running') - - subparsers.required = True - return parser.parse_args() +from plinth.actions import privileged def _flush_iptables_rules(): @@ -81,26 +62,11 @@ def set_firewall_backend(backend): action_utils.service_restart('firewalld') -def subcommand_setup(_): +@privileged +def setup(): """Perform basic firewalld setup.""" action_utils.service_enable('firewalld') - subprocess.call(['firewall-cmd', '--set-default-zone=external']) + subprocess.run(['firewall-cmd', '--set-default-zone=external'], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, + check=True) set_firewall_backend('nftables') - - -def subcommand_get_status(_): - """Print status of the firewalld service""" - subprocess.call(['firewall-cmd', '--state']) - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == "__main__": - main() diff --git a/plinth/modules/firewall/templates/firewall.html b/plinth/modules/firewall/templates/firewall.html index e87d4618c..a9dc0eb9d 100644 --- a/plinth/modules/firewall/templates/firewall.html +++ b/plinth/modules/firewall/templates/firewall.html @@ -15,97 +15,82 @@ <h3>{% trans "Status" %}</h3> - {% if firewall_status == 'not_running' %} + <div class="table-responsive"> + <table class='table table-autowidth'> + <thead> + <th>{% trans "Service/Port" %}</th> + <th>{% trans "Status" %}</th> + </thead> - <p> - {% blocktrans trimmed %} - Firewall daemon is not running. Please run it. Firewall comes - enabled by default on {{ box_name }}. On any Debian based - system (such as {{ box_name }}) you may run it using the - command 'service firewalld start' or in case of a system with - systemd 'systemctl start firewalld'. - {% endblocktrans %} - </p> - - {% else %} - - <div class="table-responsive"> - <table class='table table-autowidth'> - <thead> - <th>{% trans "Service/Port" %}</th> - <th>{% trans "Status" %}</th> - </thead> - - <tbody> - {% for component in components|dictsort:"name" %} - {% if component.ports %} - <tr> - <td class="app-name"> - <a class="dropdown-toggle" href="#" - data-toggle="collapse" role="button" - data-target=".{{component.component_id}}" - aria-expanded="false" - aria-controls="{{component.component_id}}"> - {{ component.name }}</a> + <tbody> + {% for component in components|dictsort:"name" %} + {% if component.ports %} + <tr> + <td class="app-name"> + <a class="dropdown-toggle" href="#" + data-toggle="collapse" role="button" + data-target=".{{component.component_id}}" + aria-expanded="false" + aria-controls="{{component.component_id}}"> + {{ component.name }}</a> + </td> + <td class="app-status"> + {% if component.is_enabled %} + <span class='badge badge-success'> + {% trans "Enabled" %}</span> + {% else %} + <span class='badge badge-warning'> + {% trans "Disabled" %}</span> + {% endif %} + </td> + </tr> + {% for port in component.ports_details %} + <tr class="collapse {{component.component_id}}"> + <td class='service'> + <span class="service-name">{{ port.name }}</span>: + {% for port_number, protocol in port.details %} + {{ port_number }}/{{ protocol }} + {% endfor %} </td> - <td class="app-status"> - {% if component.is_enabled %} + <td class="service-status"> + {% if port.name in internal_enabled_ports and port.name in external_enabled_ports %} <span class='badge badge-success'> - {% trans "Enabled" %}</span> - {% else %} + {% trans "Permitted" %}</span> + {% elif port.name in internal_enabled_ports %} <span class='badge badge-warning'> - {% trans "Disabled" %}</span> + {% trans "Permitted (internal only)" %}</span> + {% elif port.name in external_enabled_ports %} + <span class='badge badge-warning'> + {% trans "Permitted (external only)" %}</span> + {% else %} + <span class='badge badge-danger'> + {% trans "Blocked" %}</span> {% endif %} </td> </tr> - {% for port in component.ports_details %} - <tr class="collapse {{component.component_id}}"> - <td class='service'> - <span class="service-name">{{ port.name }}</span>: - {% for port_number, protocol in port.details %} - {{ port_number }}/{{ protocol }} - {% endfor %} - </td> - <td class="service-status"> - {% if port.name in internal_enabled_ports and port.name in external_enabled_ports %} - <span class='badge badge-success'> - {% trans "Permitted" %}</span> - {% elif port.name in internal_enabled_ports %} - <span class='badge badge-warning'> - {% trans "Permitted (internal only)" %}</span> - {% elif port.name in external_enabled_ports %} - <span class='badge badge-warning'> - {% trans "Permitted (external only)" %}</span> - {% else %} - <span class='badge badge-danger'> - {% trans "Blocked" %}</span> - {% endif %} - </td> - </tr> - {% endfor %} - {% endif %} - {% endfor %} - </tbody> - </table> - </div> + {% endfor %} + {% endif %} + {% endfor %} + </tbody> + </table> + </div> - <p> - <em> - {% blocktrans trimmed %} - The operation of the firewall is automatic. When you enable - a service it is also permitted in the firewall and when you - disable a service it is also disabled in the firewall. - {% endblocktrans %} - </em> - </p> - - <h3>{%trans "Advanced" %} </h3> - <p> + <p> + <em> {% blocktrans trimmed %} - Advanced firewall operations such as opening custom ports are provided - by the <a href="/_cockpit/network/firewall">Cockpit</a> app. + The operation of the firewall is automatic. When you enable + a service it is also permitted in the firewall and when you + disable a service it is also disabled in the firewall. {% endblocktrans %} - </p> - {% endif %} + </em> + </p> + + <h3>{%trans "Advanced" %} </h3> + <p> + {% blocktrans trimmed %} + Advanced firewall operations such as opening custom ports are provided + by the <a href="/_cockpit/network/firewall">Cockpit</a> app. + {% endblocktrans %} + </p> {% endblock %} diff --git a/plinth/modules/firewall/views.py b/plinth/modules/firewall/views.py index c517a231a..69fc1d366 100644 --- a/plinth/modules/firewall/views.py +++ b/plinth/modules/firewall/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure a firewall. -""" +"""FreedomBox app to configure a firewall.""" from plinth import views from plinth.modules import firewall @@ -11,23 +9,16 @@ from . import components class FirewallAppView(views.AppView): """Serve firewall index page.""" + app_id = 'firewall' template_name = 'firewall.html' def get_context_data(self, *args, **kwargs): """Add additional context data for the template.""" context = super().get_context_data(*args, **kwargs) - - status = 'running' if firewall.get_enabled_status() else 'not_running' - context['firewall_status'] = status - - if status == 'running': - context['components'] = components.Firewall.list() - internal_enabled_ports = firewall.get_enabled_services( - zone='internal') - external_enabled_ports = firewall.get_enabled_services( - zone='external') - context['internal_enabled_ports'] = internal_enabled_ports - context['external_enabled_ports'] = external_enabled_ports - + context['components'] = components.Firewall.list() + internal_enabled_ports = firewall.get_enabled_services(zone='internal') + external_enabled_ports = firewall.get_enabled_services(zone='external') + context['internal_enabled_ports'] = internal_enabled_ports + context['external_enabled_ports'] = external_enabled_ports return context From b91f1cf922184b0119c55b34230e11659a96320a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 1 Sep 2022 23:13:31 -0700 Subject: [PATCH 30/90] gitweb: Use privileged decorator for actions Tests: - Functions tests work - Initial setup works - Global default branch is set to 'main' - Creating an repository works - Cloning a repository works - Progress is shown on the app page - List of repositories is shown properly in the app page - Deleting a repo works - Editing a repository works - Repository information is shown properly in the form - Renaming a repository - Setting description - Setting owner - Setting a repository private/public - Setting default branch (list of branches is shown properly) - Error is thrown properly when a remote repository does not exist - Errors are handled properly when creating/editing/deleting repo Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- plinth/modules/gitweb/__init__.py | 108 ++----- plinth/modules/gitweb/forms.py | 9 +- .../modules/gitweb/privileged.py | 288 ++++++------------ plinth/modules/gitweb/tests/test_actions.py | 129 -------- .../modules/gitweb/tests/test_functional.py | 2 +- .../modules/gitweb/tests/test_privileged.py | 114 +++++++ plinth/modules/gitweb/tests/test_views.py | 52 ++-- plinth/modules/gitweb/views.py | 18 +- 8 files changed, 271 insertions(+), 449 deletions(-) rename actions/gitweb => plinth/modules/gitweb/privileged.py (50%) mode change 100755 => 100644 delete mode 100644 plinth/modules/gitweb/tests/test_actions.py create mode 100644 plinth/modules/gitweb/tests/test_privileged.py diff --git a/plinth/modules/gitweb/__init__.py b/plinth/modules/gitweb/__init__.py index f6e958377..ead2bdc3b 100644 --- a/plinth/modules/gitweb/__init__.py +++ b/plinth/modules/gitweb/__init__.py @@ -1,24 +1,19 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Gitweb. -""" +"""FreedomBox app to configure Gitweb.""" -import json import os from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu -from plinth.errors import ActionError from plinth.modules.apache.components import Webserver from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages -from . import manifest +from . import manifest, privileged from .forms import is_repo_url from .manifest import GIT_REPO_PATH @@ -129,7 +124,7 @@ class GitwebApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('gitweb', ['setup']) + privileged.setup() self.enable() @@ -161,36 +156,31 @@ class GitwebBackupRestore(BackupRestore): self.app.update_service_access() -def repo_exists(name): - """Check whether a remote repository exists.""" - try: - actions.run('gitweb', ['check-repo-exists', '--url', name]) - except ActionError: - return False - - return True - - def have_public_repos(repos): - """Check for public repositories""" + """Check for public repositories.""" return any((repo['access'] == 'public' for repo in repos)) def create_repo(repo, repo_description, owner, is_private): """Create a new repository or clone a remote repository.""" - args = ['--description', repo_description, '--owner', owner] - if is_private: - args.append('--is-private') + kwargs = { + 'url': None, + 'name': None, + 'description': repo_description, + 'owner': owner, + 'is_private': is_private + } + if is_repo_url(repo): - args = ['create-repo', '--url', repo] + args + kwargs['url'] = repo # create a repo directory and set correct access rights - actions.superuser_run('gitweb', args + ['--prepare-only']) + privileged.create_repo(prepare_only=True, **kwargs) # start cloning in background - actions.superuser_run('gitweb', args + ['--skip-prepare'], - run_in_background=True) + privileged.create_repo(skip_prepare=True, _run_in_background=True, + **kwargs) else: - args = ['create-repo', '--name', repo] + args - actions.superuser_run('gitweb', args) + kwargs['name'] = repo + privileged.create_repo(**kwargs) def get_repo_list(): @@ -223,8 +213,7 @@ def get_repo_list(): def repo_info(repo): """Get information about repository.""" - output = actions.run('gitweb', ['repo-info', '--name', repo]) - info = json.loads(output) + info = privileged.repo_info(repo) if info['access'] == 'private': info['is_private'] = True else: @@ -234,72 +223,25 @@ def repo_info(repo): return info -def _rename_repo(oldname, newname): - """Rename a repository.""" - args = ['rename-repo', '--oldname', oldname, '--newname', newname] - actions.superuser_run('gitweb', args) - - -def _set_default_branch(repo, branch): - """Set default branch of the repository.""" - args = [ - 'set-default-branch', - '--name', - repo, - '--branch', - branch, - ] - actions.superuser_run('gitweb', args) - - -def _set_repo_description(repo, repo_description): - """Set description of the repository.""" - args = [ - 'set-repo-description', - '--name', - repo, - '--description', - repo_description, - ] - actions.superuser_run('gitweb', args) - - -def _set_repo_owner(repo, owner): - """Set repository's owner name.""" - args = ['set-repo-owner', '--name', repo, '--owner', owner] - actions.superuser_run('gitweb', args) - - -def _set_repo_access(repo, access): - """Set repository's owner name.""" - args = ['set-repo-access', '--name', repo, '--access', access] - actions.superuser_run('gitweb', args) - - def edit_repo(form_initial, form_cleaned): """Edit repository data.""" repo = form_initial['name'] if form_cleaned['name'] != repo: - _rename_repo(repo, form_cleaned['name']) + privileged.rename_repo(repo, form_cleaned['name']) repo = form_cleaned['name'] if form_cleaned['description'] != form_initial['description']: - _set_repo_description(repo, form_cleaned['description']) + privileged.set_repo_description(repo, form_cleaned['description']) if form_cleaned['owner'] != form_initial['owner']: - _set_repo_owner(repo, form_cleaned['owner']) + privileged.set_repo_owner(repo, form_cleaned['owner']) if form_cleaned['is_private'] != form_initial['is_private']: if form_cleaned['is_private']: - _set_repo_access(repo, 'private') + privileged.set_repo_access(repo, 'private') else: - _set_repo_access(repo, 'public') + privileged.set_repo_access(repo, 'public') if form_cleaned['default_branch'] != form_initial['default_branch']: - _set_default_branch(repo, form_cleaned['default_branch']) - - -def delete_repo(repo): - """Delete a repository.""" - actions.superuser_run('gitweb', ['delete-repo', '--name', repo]) + privileged.set_default_branch(repo, form_cleaned['default_branch']) diff --git a/plinth/modules/gitweb/forms.py b/plinth/modules/gitweb/forms.py index 555f8918b..76ba8a314 100644 --- a/plinth/modules/gitweb/forms.py +++ b/plinth/modules/gitweb/forms.py @@ -3,7 +3,6 @@ Django form for configuring Gitweb. """ -import json import re from urllib.parse import urlparse @@ -12,14 +11,14 @@ from django.core.exceptions import ValidationError from django.core.validators import URLValidator from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth.modules import gitweb +from . import privileged + def _get_branches(repo): """Get all the branches in the repository.""" - branch_data = json.loads( - actions.run('gitweb', ['get-branches', '--name', repo])) + branch_data = privileged.get_branches(repo) default_branch = branch_data['default_branch'] branches = branch_data['branches'] @@ -113,7 +112,7 @@ class CreateRepoForm(forms.Form): _('A repository with this name already exists.')) if is_repo_url(name): - if not gitweb.repo_exists(name): + if not privileged.repo_exists(name): raise ValidationError('Remote repository is not available.') return name diff --git a/actions/gitweb b/plinth/modules/gitweb/privileged.py old mode 100755 new mode 100644 similarity index 50% rename from actions/gitweb rename to plinth/modules/gitweb/privileged.py index 124e55650..3bb213eed --- a/actions/gitweb +++ b/plinth/modules/gitweb/privileged.py @@ -1,145 +1,40 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Gitweb. -""" +"""Configuration helper for Gitweb.""" -import argparse import configparser -import json import logging import os import re import shutil import subprocess -import sys import time +from typing import Any, Optional from plinth import action_utils +from plinth.actions import privileged from plinth.modules.gitweb.forms import RepositoryValidator, get_name_from_url from plinth.modules.gitweb.manifest import GIT_REPO_PATH logger = logging.getLogger(__name__) -class ValidateRepoName(argparse.Action): +def validate_repo_name(name: str) -> str: """Validate a repository name and add .git extension if necessary.""" + RepositoryValidator()(name) + if not name.endswith('.git'): + name = name + '.git' - def __call__(self, parser, namespace, values, option_string=None): - RepositoryValidator()(values) - if not values.endswith('.git'): - values = values + '.git' - setattr(namespace, self.dest, values) + return name -class ValidateRepoUrl(argparse.Action): +def validate_repo_url(url: str) -> str: """Validate a repository URL.""" - - def __call__(self, parser, namespace, values, option_string=None): - RepositoryValidator(input_should_be='url')(values) - setattr(namespace, self.dest, values) + RepositoryValidator(input_should_be='url')(url) + return url -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser( - 'setup', help='Perform post-installation operations for Gitweb') - - subparser = subparsers.add_parser('create-repo', - help='Create a new repository') - group = subparser.add_mutually_exclusive_group(required=True) - group.add_argument('--name', action=ValidateRepoName, - help='Name of the repository') - group.add_argument('--url', action=ValidateRepoUrl, - help='URL of the remote repository') - subparser.add_argument('--description', required=True, - help='Description of the repository') - subparser.add_argument('--owner', required=True, - help='Repository’s owner name') - subparser.add_argument( - '--is-private', required=False, default=False, action='store_true', - help='Allow only authorized users to access this repository') - subparser.add_argument( - '--keep-ownership', required=False, default=False, action="store_true", - help='Do not chanege ownership of the repository directory') - subparser.add_argument('--prepare-only', required=False, default=False, - action='store_true', - help='Run preparation tasks for cloning.') - subparser.add_argument('--skip-prepare', required=False, default=False, - action='store_true', - help='Skip preparation tasks for cloning.') - - subparser = subparsers.add_parser( - 'repo-info', help='Get information about the repository') - subparser.add_argument('--name', required=True, action=ValidateRepoName, - help='Name of the repository') - - subparser = subparsers.add_parser( - 'check-repo-exists', help='Check whether the remote repository exists') - subparser.add_argument('--url', required=True, action=ValidateRepoUrl, - help='URL of the remote repository') - - subparser = subparsers.add_parser('rename-repo', - help='Rename an repository') - subparser.add_argument('--oldname', required=True, action=ValidateRepoName, - help='Old name of the repository') - subparser.add_argument('--newname', required=True, action=ValidateRepoName, - help='New name of the repository') - - subparser = subparsers.add_parser( - 'set-default-branch', help='Set default branch of the repository') - subparser.add_argument('--name', required=True, action=ValidateRepoName, - help='Name of the repository') - subparser.add_argument('--branch', required=True, - help='Name of the branch') - - subparser = subparsers.add_parser( - 'get-branches', help='Get all the branches of the repository') - subparser.add_argument('--name', required=True, action=ValidateRepoName, - help='Name of the repository') - - subparser = subparsers.add_parser('set-repo-description', - help='Set description of the repository') - subparser.add_argument('--name', required=True, action=ValidateRepoName, - help='Name of the repository') - subparser.add_argument('--description', required=True, - help='Description of the repository') - - subparser = subparsers.add_parser('set-repo-owner', - help='Set repository\'s owner name') - subparser.add_argument('--name', required=True, action=ValidateRepoName, - help='Name of the repository') - subparser.add_argument('--owner', required=True, - help='Repository’s owner name') - - subparser = subparsers.add_parser( - 'set-repo-access', help='Set repository as private or public') - subparser.add_argument('--name', required=True, action=ValidateRepoName, - help='Name of the repository') - subparser.add_argument('--access', required=True, - choices=['public', 'private'], help='Access status') - - subparser = subparsers.add_parser('delete-repo', - help='Delete an existing repository') - subparser.add_argument('--name', required=True, action=ValidateRepoName, - help='Name of the repository to remove') - - subparsers.required = True - args = parser.parse_args() - if args.subcommand == 'create-repo' and args.name: - if args.prepare_only: - parser.error('--prepare-only can be set when using --url') - - if args.skip_prepare: - parser.error('--skip-prepare can be set when using --url') - - return args - - -def subcommand_setup(_): +@privileged +def setup(): """Disable default Apache2 Gitweb configuration.""" action_utils.webserver_disable('gitweb') if not _get_global_default_branch(): @@ -215,9 +110,9 @@ def _clone_with_progress_report(url, repo_dir): raise RuntimeError('Git repository cloning failed.', errors) -def _prepare_clone_repo(arguments): +def _prepare_clone_repo(url: str, is_private: bool): """Prepare cloning a repository.""" - repo_name = get_name_from_url(arguments.url) + repo_name = get_name_from_url(url) if not repo_name.endswith('.git'): repo_name = repo_name + '.git' @@ -226,7 +121,7 @@ def _prepare_clone_repo(arguments): status_file = os.path.join(repo_dir, 'clone_progress') try: - if arguments.is_private: + if is_private: _set_access_status(repo_name, 'private') with open(status_file, 'w', encoding='utf-8') as file_handle: file_handle.write('0') @@ -255,9 +150,8 @@ def _clone_status_line_to_percent(line): return None -def _clone_repo(arguments): +def _clone_repo(url: str, description: str, owner: str, keep_ownership: bool): """Clone a repository.""" - url = arguments.url repo = get_name_from_url(url) if not repo.endswith('.git'): repo = repo + '.git' @@ -271,26 +165,26 @@ def _clone_repo(arguments): shutil.move(os.path.join(repo_temp_path, item), repo_path) shutil.rmtree(repo_temp_path) - if not arguments.keep_ownership: + if not keep_ownership: subprocess.check_call(['chown', '-R', 'www-data:www-data', repo], cwd=GIT_REPO_PATH) - _set_repo_description(repo, arguments.description) - _set_repo_owner(repo, arguments.owner) + _set_repo_description(repo, description) + _set_repo_owner(repo, owner) -def _create_repo(arguments): +def _create_repo(repo: str, description: str, owner: str, is_private: bool, + keep_ownership: bool): """Create an empty repository.""" - repo = arguments.name try: subprocess.check_call(['git', 'init', '-q', '--bare', repo], cwd=GIT_REPO_PATH) - if not arguments.keep_ownership: + if not keep_ownership: subprocess.check_call(['chown', '-R', 'www-data:www-data', repo], cwd=GIT_REPO_PATH) - _set_repo_description(repo, arguments.description) - _set_repo_owner(repo, arguments.owner) - if arguments.is_private: + _set_repo_description(repo, description) + _set_repo_owner(repo, owner) + if is_private: _set_access_status(repo, 'private') except (subprocess.CalledProcessError, OSError): repo_path = os.path.join(GIT_REPO_PATH, repo) @@ -363,7 +257,7 @@ def _get_access_status(repo): def _set_access_status(repo, status): - """Set repository as private or public""" + """Set repository as private or public.""" private_file = os.path.join(GIT_REPO_PATH, repo, 'private') if status == 'private': open(private_file, 'a', encoding='utf-8') @@ -381,30 +275,30 @@ def _get_branches(repo): return output.decode().strip().split() -def subcommand_get_branches(arguments): +@privileged +def get_branches(name: str) -> dict[str, Any]: """Check whether a branch exists in the repository.""" - repo = arguments.name - - print( - json.dumps( - dict(default_branch=_get_default_branch(repo), - branches=_get_branches(repo)))) + repo = validate_repo_name(name) + return dict(default_branch=_get_default_branch(repo), + branches=_get_branches(repo)) -def subcommand_rename_repo(arguments): +@privileged +def rename_repo(old_name: str, new_name: str): """Rename a repository.""" - oldpath = os.path.join(GIT_REPO_PATH, arguments.oldname) - newpath = os.path.join(GIT_REPO_PATH, arguments.newname) + old_name = validate_repo_name(old_name) + new_name = validate_repo_name(new_name) + oldpath = os.path.join(GIT_REPO_PATH, old_name) + newpath = os.path.join(GIT_REPO_PATH, new_name) os.rename(oldpath, newpath) -def subcommand_set_default_branch(arguments): +@privileged +def set_default_branch(name: str, branch: str): """Set description of the repository.""" - repo = arguments.name - branch = arguments.branch - + repo = validate_repo_name(name) if branch not in _get_branches(repo): - sys.exit('No such branch.') + raise ValueError('No such branch') subprocess.check_call([ 'git', '-C', repo, 'symbolic-ref', 'HEAD', @@ -412,71 +306,81 @@ def subcommand_set_default_branch(arguments): ], cwd=GIT_REPO_PATH) -def subcommand_set_repo_description(arguments): +@privileged +def set_repo_description(name: str, description: str): """Set description of the repository.""" - _set_repo_description(arguments.name, arguments.description) + repo = validate_repo_name(name) + _set_repo_description(repo, description) -def subcommand_set_repo_owner(arguments): +@privileged +def set_repo_owner(name: str, owner: str): """Set repository's owner name.""" - _set_repo_owner(arguments.name, arguments.owner) + repo = validate_repo_name(name) + _set_repo_owner(repo, owner) -def subcommand_set_repo_access(arguments): +@privileged +def set_repo_access(name: str, access: str): """Set repository's access status.""" - _set_access_status(arguments.name, arguments.access) + repo = validate_repo_name(name) + if access not in ('public', 'private'): + raise ValueError('Invalid access parameter') + + _set_access_status(repo, access) -def subcommand_repo_info(arguments): +@privileged +def repo_info(name: str) -> dict[str, str]: """Get information about repository.""" - repo_path = os.path.join(GIT_REPO_PATH, arguments.name) + repo = validate_repo_name(name) + repo_path = os.path.join(GIT_REPO_PATH, repo) if not os.path.exists(repo_path): raise RuntimeError('Repository not found') - print( - json.dumps( - dict( - name=arguments.name[:-4], - description=_get_repo_description(arguments.name), - owner=_get_repo_owner(arguments.name), - access=_get_access_status(arguments.name), - default_branch=_get_default_branch(arguments.name), - ))) + return dict(name=repo[:-4], description=_get_repo_description(repo), + owner=_get_repo_owner(repo), access=_get_access_status(repo), + default_branch=_get_default_branch(repo)) -def subcommand_create_repo(arguments): +@privileged +def create_repo(url: Optional[str] = None, name: Optional[str] = None, + description: str = '', owner: str = '', + keep_ownership: bool = False, is_private: bool = False, + skip_prepare: bool = False, prepare_only: bool = False): """Create a new or clone a remote repository.""" - if arguments.url: - if not arguments.skip_prepare: - _prepare_clone_repo(arguments) + if url: + url = validate_repo_url(url) - if not arguments.prepare_only: - _clone_repo(arguments) - else: - _create_repo(arguments) + if name: + repo = validate_repo_name(name) + + if url: + if not skip_prepare: + _prepare_clone_repo(url, is_private) + + if not prepare_only: + _clone_repo(url, description, owner, keep_ownership) + elif repo is not None: + _create_repo(repo, description, owner, is_private, keep_ownership) -def subcommand_check_repo_exists(arguments): - """Check whether remote repository exists.""" +@privileged +def repo_exists(url: str) -> bool: + """Return whether remote repository exists.""" + url = validate_repo_url(url) env = dict(os.environ, GIT_TERMINAL_PROMPT='0') - subprocess.check_call(['git', 'ls-remote', arguments.url, 'HEAD'], - timeout=10, env=env) + try: + subprocess.check_call(['git', 'ls-remote', url, 'HEAD'], timeout=10, + env=env) + return True + except subprocess.CalledProcessError: + return False -def subcommand_delete_repo(arguments): +@privileged +def delete_repo(name: str): """Delete a git repository.""" - repo_path = os.path.join(GIT_REPO_PATH, arguments.name) + repo = validate_repo_name(name) + repo_path = os.path.join(GIT_REPO_PATH, repo) shutil.rmtree(repo_path) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/gitweb/tests/test_actions.py b/plinth/modules/gitweb/tests/test_actions.py deleted file mode 100644 index c76008289..000000000 --- a/plinth/modules/gitweb/tests/test_actions.py +++ /dev/null @@ -1,129 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Test module for gitweb module operations. -""" - -import json - -import pytest -from django.forms import ValidationError - -REPO_NAME = 'Test-repo' -REPO_DATA = { - 'name': REPO_NAME, - 'description': '', - 'owner': '', - 'access': 'private', -} - -actions_name = 'gitweb' - - -@pytest.fixture(autouse=True) -def fixture_set_repo_path(actions_module, tmpdir): - """Set a repository path in the actions module.""" - actions_module.GIT_REPO_PATH = str(tmpdir) - - -@pytest.fixture(name='existing_repo') -def fixture_existing_repo(call_action): - """A fixture to create a repository.""" - try: - call_action(['delete-repo', '--name', REPO_NAME]) - except FileNotFoundError: - pass - - call_action([ - 'create-repo', '--name', REPO_NAME, '--description', '', '--owner', '', - '--is-private', '--keep-ownership' - ]) - - -def test_create_repo(call_action): - """Test creating a repository.""" - call_action([ - 'create-repo', '--name', REPO_NAME, '--description', '', '--owner', '', - '--is-private', '--keep-ownership' - ]) - repo = json.loads(call_action(['repo-info', '--name', REPO_NAME])) - default_branch = repo.pop('default_branch') - - assert repo == REPO_DATA - assert len(default_branch) > 0 - - -def test_change_repo_medatada(call_action, existing_repo): - """Test change a metadata of the repository.""" - new_data = { - 'name': REPO_NAME, - 'description': 'description2', - 'owner': 'owner2', - 'access': 'public', - } - - call_action([ - 'set-repo-description', '--name', REPO_NAME, '--description', - new_data['description'] - ]) - call_action( - ['set-repo-owner', '--name', REPO_NAME, '--owner', new_data['owner']]) - call_action([ - 'set-repo-access', '--name', REPO_NAME, '--access', new_data['access'] - ]) - repo = json.loads(call_action(['repo-info', '--name', REPO_NAME])) - del repo['default_branch'] - - assert repo == new_data - - -def test_rename_repository(call_action, existing_repo): - """Test renaming a repository.""" - new_name = 'Test-repo_2' - - call_action(['rename-repo', '--oldname', REPO_NAME, '--newname', new_name]) - with pytest.raises(RuntimeError, match='Repository not found'): - call_action(['repo-info', '--name', REPO_NAME]) - repo = json.loads(call_action(['repo-info', '--name', new_name])) - - assert repo['name'] == new_name - - -def test_get_branches(call_action, existing_repo): - """Test getting all the branches of the repository.""" - result = json.loads(call_action(['get-branches', '--name', REPO_NAME])) - - assert 'default_branch' in result - assert result['branches'] == [] - - -def test_delete_repository(call_action, existing_repo): - """Test deleting a repository.""" - call_action(['delete-repo', '--name', REPO_NAME]) - - with pytest.raises(RuntimeError, match='Repository not found'): - call_action(['repo-info', '--name', REPO_NAME]) - - -@pytest.mark.parametrize( - 'name', - ['.Test-repo', 'Test-repo.git.git', '/root/Test-repo', 'Test-repö']) -def test_action_create_repo_with_invalid_names(call_action, name): - """Test that creating repository with invalid names fails.""" - with pytest.raises(ValidationError): - call_action([ - 'create-repo', '--name', name, '--description', '', '--owner', '', - '--keep-ownership' - ]) - - -@pytest.mark.parametrize('url', [ - 'Test-repo', 'file://root/Test-repo', 'localhost/Test-repo', - 'ssh://localhost/Test-repo', 'https://localhost/.Test-repo' -]) -def test_action_create_repo_with_invalid_urls(call_action, url): - """Test that cloning repository with invalid URL fails.""" - with pytest.raises(ValidationError): - call_action([ - 'create-repo', '--url', url, '--description', '', '--owner', '', - '--keep-ownership' - ]) diff --git a/plinth/modules/gitweb/tests/test_functional.py b/plinth/modules/gitweb/tests/test_functional.py index 26f85b552..4eb2ed558 100644 --- a/plinth/modules/gitweb/tests/test_functional.py +++ b/plinth/modules/gitweb/tests/test_functional.py @@ -237,7 +237,7 @@ def _gitweb_git_command_is_successful(command, cwd): if process.returncode != 0: if 'Authentication failed' in process.stderr.decode(): return False - print(process.stdout.decode()) + process.check_returncode() # Raise exception return True diff --git a/plinth/modules/gitweb/tests/test_privileged.py b/plinth/modules/gitweb/tests/test_privileged.py new file mode 100644 index 000000000..d837ad51a --- /dev/null +++ b/plinth/modules/gitweb/tests/test_privileged.py @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Test module for gitweb module operations.""" + +import pytest +from django.forms import ValidationError + +from plinth.modules.gitweb import privileged + +REPO_NAME = 'Test-repo' +REPO_DATA = { + 'name': REPO_NAME, + 'description': '', + 'owner': '', + 'access': 'private', +} + +pytestmark = pytest.mark.usefixtures('mock_privileged') +privileged_modules_to_mock = ['plinth.modules.gitweb.privileged'] + + +@pytest.fixture(autouse=True) +def fixture_set_repo_path(tmpdir): + """Set a repository path in the actions module.""" + privileged.GIT_REPO_PATH = str(tmpdir) + + +@pytest.fixture(name='existing_repo') +def fixture_existing_repo(): + """A fixture to create a repository.""" + try: + privileged.delete_repo(REPO_NAME) + except FileNotFoundError: + pass + + privileged.create_repo(name=REPO_NAME, description='', owner='', + keep_ownership=True, is_private=True) + + +def test_create_repo(): + """Test creating a repository.""" + privileged.create_repo(name=REPO_NAME, description='', owner='', + is_private=True, keep_ownership=True) + repo = privileged.repo_info(REPO_NAME) + default_branch = repo.pop('default_branch') + + assert repo == REPO_DATA + assert default_branch + + +def test_change_repo_medatada(existing_repo): + """Test change a metadata of the repository.""" + new_data = { + 'name': REPO_NAME, + 'description': 'description2', + 'owner': 'owner2', + 'access': 'public', + } + + privileged.set_repo_description(REPO_NAME, new_data['description']) + privileged.set_repo_owner(REPO_NAME, new_data['owner']) + privileged.set_repo_access(REPO_NAME, new_data['access']) + repo = privileged.repo_info(REPO_NAME) + del repo['default_branch'] + + assert repo == new_data + + +def test_rename_repository(existing_repo): + """Test renaming a repository.""" + new_name = 'Test-repo_2' + + privileged.rename_repo(REPO_NAME, new_name) + with pytest.raises(RuntimeError, match='Repository not found'): + privileged.repo_info(REPO_NAME) + + repo = privileged.repo_info(new_name) + assert repo['name'] == new_name + + +def test_get_branches(existing_repo): + """Test getting all the branches of the repository.""" + result = privileged.get_branches(REPO_NAME) + + assert 'default_branch' in result + assert result['branches'] == [] + + +def test_delete_repository(existing_repo): + """Test deleting a repository.""" + privileged.delete_repo(REPO_NAME) + + with pytest.raises(RuntimeError, match='Repository not found'): + privileged.repo_info(REPO_NAME) + + +@pytest.mark.parametrize( + 'name', + ['.Test-repo', 'Test-repo.git.git', '/root/Test-repo', 'Test-repö']) +def test_action_create_repo_with_invalid_names(name): + """Test that creating repository with invalid names fails.""" + with pytest.raises(ValidationError): + privileged.create_repo(name=name, description='', owner='', + keep_ownership=True) + + +@pytest.mark.parametrize('url', [ + 'Test-repo', 'file://root/Test-repo', 'localhost/Test-repo', + 'ssh://localhost/Test-repo', 'https://localhost/.Test-repo' +]) +def test_action_create_repo_with_invalid_urls(url): + """Test that cloning repository with invalid URL fails.""" + with pytest.raises(ValidationError): + privileged.create_repo(url=url, description='', owner='', + keep_ownership=True) diff --git a/plinth/modules/gitweb/tests/test_views.py b/plinth/modules/gitweb/tests/test_views.py index ce69dc507..1bf20ffec 100644 --- a/plinth/modules/gitweb/tests/test_views.py +++ b/plinth/modules/gitweb/tests/test_views.py @@ -3,7 +3,6 @@ Tests for gitweb views. """ -import json from unittest.mock import Mock, patch import pytest @@ -12,7 +11,6 @@ from django.contrib.messages.storage.fallback import FallbackStorage from django.http.response import Http404 from plinth import module_loader -from plinth.errors import ActionError from plinth.modules.gitweb import views # For all tests, use plinth.urls instead of urls configured for testing @@ -48,31 +46,28 @@ def fixture_gitweb_urls(): yield -def action_run(*args, **kwargs): - """Action return values.""" - subcommand = args[1][0] - if subcommand == 'repo-info': - return json.dumps(EXISTING_REPOS[0]) - - elif subcommand == 'check-repo-exists': - return True - - elif subcommand == 'get-branches': - return json.dumps({ - "default_branch": "main", - "branches": ["main", "branch1"] - }) - - return None - - @pytest.fixture(autouse=True) def gitweb_patch(): """Patch gitweb.""" + privileged = 'plinth.modules.gitweb.privileged' with patch('plinth.modules.gitweb.get_repo_list') as get_repo_list, \ - patch('plinth.app.App.get') as app_get, \ - patch('plinth.actions.superuser_run', side_effect=action_run), \ - patch('plinth.actions.run', side_effect=action_run): + patch('plinth.app.App.get') as app_get, \ + patch(f'{privileged}.create_repo'), \ + patch(f'{privileged}.repo_exists') as repo_exists,\ + patch(f'{privileged}.repo_info') as repo_info, \ + patch(f'{privileged}.rename_repo'), \ + patch(f'{privileged}.set_repo_description'), \ + patch(f'{privileged}.set_repo_owner'), \ + patch(f'{privileged}.set_repo_access'), \ + patch(f'{privileged}.set_default_branch'), \ + patch(f'{privileged}.delete_repo'), \ + patch(f'{privileged}.get_branches') as get_branches: + repo_exists.return_value = True + repo_info.return_value = dict(EXISTING_REPOS[0]) + get_branches.return_value = { + 'default_branch': 'main', + 'branches': ['main', 'branch1'] + } get_repo_list.return_value = [{ 'name': EXISTING_REPOS[0]['name'] }, { @@ -163,7 +158,7 @@ def test_create_repo_failed_view(rf): general_error_message = "An error occurred while creating the repository." error_description = 'some error' with patch('plinth.modules.gitweb.create_repo', - side_effect=ActionError('gitweb', '', error_description)): + side_effect=PermissionError(error_description)): form_data = { 'gitweb-name': 'something_other', 'gitweb-description': '', @@ -198,7 +193,8 @@ def test_clone_repo_view(rf): def test_clone_repo_missing_remote_view(rf): """Test that cloning non-existing repo shows correct error message.""" - with patch('plinth.modules.gitweb.repo_exists', return_value=False): + with patch('plinth.modules.gitweb.privileged.repo_exists', + return_value=False): form_data = { 'gitweb-name': 'https://example.com/test.git', 'gitweb-description': '', @@ -306,7 +302,7 @@ def test_edit_repository_no_change_view(rf): def test_edit_repository_failed_view(rf): """Test that failed repo editing sends correct error message.""" with patch('plinth.modules.gitweb.edit_repo', - side_effect=ActionError('Error')): + side_effect=PermissionError('Error')): form_data = { 'gitweb-name': 'something_other', 'gitweb-description': 'test-description', @@ -347,8 +343,8 @@ def test_delete_repository_view(rf): def test_delete_repository_fail_view(rf): """Test that failed repository deletion sends correct error message.""" - with patch('plinth.modules.gitweb.delete_repo', - side_effect=ActionError('Error')): + with patch('plinth.modules.gitweb.privileged.delete_repo', + side_effect=FileNotFoundError('Error')): response, messages = make_request(rf.post(''), views.delete, name=EXISTING_REPOS[0]['name']) diff --git a/plinth/modules/gitweb/views.py b/plinth/modules/gitweb/views.py index b6dbb088f..01f13f74f 100644 --- a/plinth/modules/gitweb/views.py +++ b/plinth/modules/gitweb/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Django views for Gitweb. -""" +"""Django views for Gitweb.""" from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin @@ -12,12 +10,11 @@ from django.urls import reverse_lazy from django.utils.translation import gettext as _ from django.views.generic import FormView -from plinth import actions from plinth import app as app_module from plinth import views -from plinth.errors import ActionError from plinth.modules import gitweb +from . import privileged from .forms import CreateRepoForm, EditRepoForm @@ -65,13 +62,12 @@ class CreateRepoView(SuccessMessageMixin, FormView): try: gitweb.create_repo(form_data['name'], form_data['description'], form_data['owner'], form_data['is_private']) - except ActionError as error: + except Exception as error: self.success_message = '' - error_text = error.args[2].split('\n')[0] messages.error( self.request, "{0} {1}".format( _('An error occurred while creating the repository.'), - error_text)) + error)) else: app_module.App.get('gitweb').update_service_access() @@ -116,7 +112,7 @@ class EditRepoView(SuccessMessageMixin, FormView): try: gitweb.edit_repo(form.initial, form_data) - except ActionError: + except Exception: messages.error(self.request, _('An error occurred during configuration.')) app_module.App.get('gitweb').update_service_access() @@ -139,9 +135,9 @@ def delete(request, name): app = app_module.App.get('gitweb') if request.method == 'POST': try: - gitweb.delete_repo(name) + privileged.delete_repo(name) messages.success(request, _('{name} deleted.').format(name=name)) - except actions.ActionError as error: + except Exception as error: messages.error( request, _('Could not delete {name}: {error}').format( From 1027b624aa951997c38e1a742ee07d1797b5190f Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Fri, 26 Aug 2022 16:43:04 -0700 Subject: [PATCH 31/90] help: Use privileged decorator for actions Tests: - Functional tests work - Accessing help/status-log/ works and last 100 logs lines are shown. - When there are no logs, '--no entries--' message is shown. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/help | 38 ------------------------------- plinth/modules/help/privileged.py | 14 ++++++++++++ plinth/modules/help/views.py | 14 ++++++------ 3 files changed, 21 insertions(+), 45 deletions(-) delete mode 100755 actions/help create mode 100644 plinth/modules/help/privileged.py diff --git a/actions/help b/actions/help deleted file mode 100755 index 1c3a58841..000000000 --- a/actions/help +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Actions for help module. -""" - -import argparse -import subprocess - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('get-logs', help='Get latest FreedomBox logs') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_get_logs(_): - """Get latest FreedomBox logs.""" - command = ['journalctl', '--no-pager', '--lines=100', '--unit=plinth'] - subprocess.run(command, check=True) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/help/privileged.py b/plinth/modules/help/privileged.py new file mode 100644 index 000000000..a1e6447e8 --- /dev/null +++ b/plinth/modules/help/privileged.py @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Actions for help module.""" + +import subprocess + +from plinth.actions import privileged + + +@privileged +def get_logs() -> str: + """Get latest FreedomBox logs.""" + command = ['journalctl', '--no-pager', '--lines=100', '--unit=plinth'] + process = subprocess.run(command, check=True, stdout=subprocess.PIPE) + return process.stdout.decode() diff --git a/plinth/modules/help/views.py b/plinth/modules/help/views.py index f18d0dd1b..a020252b7 100644 --- a/plinth/modules/help/views.py +++ b/plinth/modules/help/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Help app for FreedomBox. -""" +"""Help app for FreedomBox.""" import gzip import json @@ -18,9 +16,11 @@ from django.urls import reverse from django.utils.translation import get_language_from_request from django.utils.translation import gettext as _ -from plinth import __version__, actions, cfg +from plinth import __version__, cfg from plinth.modules.upgrades import views as upgrades_views +from . import privileged + def index(request): """Serve the index page""" @@ -162,7 +162,7 @@ def download_manual(request): def status_log(request): - """Serve the last 100 lines of plinth's status log""" - output = actions.superuser_run('help', ['get-logs']) - context = {'num_lines': 100, 'data': output} + """Serve the last 100 lines of plinth's status log.""" + logs = privileged.get_logs() + context = {'num_lines': 100, 'data': logs} return TemplateResponse(request, 'statuslog.html', context) From 24af41e6a8e3a6690657523cd4c7556ee2e9d5e9 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 25 Aug 2022 11:49:00 -0700 Subject: [PATCH 32/90] i2p: Use privileged decorator for actions Tests: - Functional tests work. - Initial setup works - Sometimes fails to write tunnel configuration (See #2127). - Favorites are created as listed in FAVORITES in resources.py - Tunnels are created: I2P HTTP Proxy, I2P HTTPS Proxy, Irc2P Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/i2p | 82 -------------------------------- plinth/modules/i2p/__init__.py | 29 +++-------- plinth/modules/i2p/privileged.py | 26 ++++++++++ 3 files changed, 32 insertions(+), 105 deletions(-) delete mode 100755 actions/i2p create mode 100644 plinth/modules/i2p/privileged.py diff --git a/actions/i2p b/actions/i2p deleted file mode 100755 index 0f5e9731b..000000000 --- a/actions/i2p +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Wrapper to list and handle system services -""" - -import argparse -import os - -from plinth import cfg -from plinth.modules.i2p.helpers import RouterEditor, TunnelEditor - -cfg.read() -module_config_path = os.path.join(cfg.config_dir, 'modules-enabled') - -I2P_CONF_DIR = '/var/lib/i2p/i2p-config' - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparser = subparsers.add_parser( - 'add-favorite', help='Add an eepsite to the list of favorites') - subparser.add_argument('--name', help='Name of the entry', required=True) - subparser.add_argument('--url', help='URL of the entry', required=True) - subparser.add_argument('--description', help='Short description', - required=False) - subparser.add_argument('--icon', help='URL to icon', required=False) - - subparser = subparsers.add_parser('set-tunnel-property', - help='Modify configuration of a tunnel') - subparser.add_argument('--name', help='Name of the tunnel', required=True) - subparser.add_argument('--property', help='Property to modify', - required=True) - subparser.add_argument('--value', help='Value to assign', required=True) - - subparsers.required = True - return parser.parse_args() - - -def subcommand_set_tunnel_property(arguments): - """Modify the configuration file for a certain tunnel.""" - editor = TunnelEditor() - editor \ - .read_conf() \ - .set_tunnel_idx(arguments.name) \ - .set_tunnel_prop(arguments.property, arguments.value) \ - .write_conf() - print('Updated "{property}" of {filename} to {value}'.format( - property=editor.calc_prop_path(arguments.property), - filename=editor.conf_filename, value=arguments.value)) - - -def subcommand_add_favorite(arguments): - """ - Adds a favorite to the router.config - - :param arguments: - :type arguments: - """ - url = arguments.url - - editor = RouterEditor() - editor.read_conf().add_favorite(arguments.name, url, arguments.description, - arguments.icon).write_conf() - - print('Added {} to favorites'.format(url)) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/i2p/__init__.py b/plinth/modules/i2p/__init__.py index aad01f1e1..b0e1458a2 100644 --- a/plinth/modules/i2p/__init__.py +++ b/plinth/modules/i2p/__init__.py @@ -1,11 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure I2P. -""" +"""FreedomBox app to configure I2P.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.daemon import Daemon @@ -16,7 +13,7 @@ from plinth.modules.i2p.resources import FAVORITES from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages -from . import manifest +from . import manifest, privileged _description = [ _('The Invisible Internet Project is an anonymous network layer intended ' @@ -103,25 +100,11 @@ class I2PApp(app_module.App): self.disable() # Add favorites to the configuration for fav in FAVORITES: - args = [ - 'add-favorite', - '--name', - fav.get('name'), - '--url', - fav.get('url'), - ] - if 'icon' in fav: - args.extend(['--icon', fav.get('icon')]) - - if 'description' in fav: - args.extend(['--description', fav.get('description')]) - - actions.superuser_run('i2p', args) + privileged.add_favorite(fav['name'], fav['url'], + fav.get('description'), fav.get('icon')) # Tunnels to all interfaces for tunnel in tunnels_to_manage: - actions.superuser_run('i2p', [ - 'set-tunnel-property', '--name', tunnel, '--property', - 'interface', '--value', '0.0.0.0' - ]) + privileged.set_tunnel_property(tunnel, 'interface', '0.0.0.0') + self.enable() diff --git a/plinth/modules/i2p/privileged.py b/plinth/modules/i2p/privileged.py new file mode 100644 index 000000000..bd3c50395 --- /dev/null +++ b/plinth/modules/i2p/privileged.py @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure I2P.""" + +from typing import Optional + +from plinth.actions import privileged +from plinth.modules.i2p.helpers import RouterEditor, TunnelEditor + + +@privileged +def set_tunnel_property(name: str, property_: str, value: str): + """Modify the configuration file for a certain tunnel.""" + editor = TunnelEditor() + editor \ + .read_conf() \ + .set_tunnel_idx(name) \ + .set_tunnel_prop(property_, value) \ + .write_conf() + + +@privileged +def add_favorite(name: str, url: str, description: Optional[str], + icon: Optional[str]): + """Add a favorite to router.config.""" + editor = RouterEditor() + editor.read_conf().add_favorite(name, url, description, icon).write_conf() From 486d56e4cbb6a7c8a094b54c9266150531ff227b Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa <sunil@medhas.org> Date: Thu, 1 Sep 2022 23:27:46 -0700 Subject: [PATCH 33/90] ikiwiki: Use privileged decorator for actions Tests: - Functional tests work. - Initial setup works - /var/www/ikiwiki is created - Shortcuts are created for existing sites after restarting FreedomBox service. - Creating a new wiki works. - The site is listed in the list of blogs/wikis - Creating a new blog works. - The site is listed in the list of blogs/wikis - Deleting a wiki works - Deleting a blog works Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org> --- actions/ikiwiki | 147 --------------------------- plinth/modules/ikiwiki/__init__.py | 14 +-- plinth/modules/ikiwiki/privileged.py | 98 ++++++++++++++++++ plinth/modules/ikiwiki/views.py | 24 ++--- 4 files changed, 111 insertions(+), 172 deletions(-) delete mode 100755 actions/ikiwiki create mode 100644 plinth/modules/ikiwiki/privileged.py diff --git a/actions/ikiwiki b/actions/ikiwiki deleted file mode 100755 index 4080f9bef..000000000 --- a/actions/ikiwiki +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for ikiwiki -""" - -import argparse -import os -import re -import shutil -import subprocess -import sys - -SETUP_WIKI = '/etc/ikiwiki/plinth-wiki.setup' -SETUP_BLOG = '/etc/ikiwiki/plinth-blog.setup' -SITE_PATH = '/var/www/ikiwiki' -WIKI_PATH = '/var/lib/ikiwiki' - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - # Setup ikiwiki site - subparsers.add_parser('setup', help='Perform first time setup operations') - - # Get wikis and blogs - subparsers.add_parser('get-sites', help='Get wikis and blogs') - - # Create a wiki - create_wiki = subparsers.add_parser('create-wiki', help='Create a wiki') - create_wiki.add_argument('--wiki_name', help='Name of new wiki') - create_wiki.add_argument('--admin_name', help='Administrator account name') - - # Create a blog - create_blog = subparsers.add_parser('create-blog', help='Create a blog') - create_blog.add_argument('--blog_name', help='Name of new blog') - create_blog.add_argument('--admin_name', help='Administrator account name') - - # Delete a wiki or blog - delete = subparsers.add_parser('delete', help='Delete a wiki or blog.') - delete.add_argument('--name', help='Name of wiki or blog to delete.') - - subparsers.required = True - return parser.parse_args() - - -def _is_safe_path(basedir, path): - """Return whether a path is safe.""" - return os.path.realpath(path).startswith(basedir) - - -def subcommand_setup(_): - """Perform first time setup operations.""" - setup() - - -def get_title(site): - """Get blog or wiki title""" - try: - with open(os.path.join(SITE_PATH, site, 'index.html'), - encoding='utf-8') as index_file: - match = re.search(r'<title>(.*)', index_file.read()) - if match: - return match[1] - except FileNotFoundError: - pass - - return site - - -def subcommand_get_sites(_): - """Get wikis and blogs.""" - if os.path.exists(SITE_PATH): - for site in os.listdir(SITE_PATH): - if not os.path.isdir(os.path.join(SITE_PATH, site)): - continue - - title = get_title(site) - print(site, title) - - -def subcommand_create_wiki(arguments): - """Create a wiki.""" - pw_bytes = sys.stdin.read().encode() - proc = subprocess.Popen([ - 'ikiwiki', '-setup', SETUP_WIKI, arguments.wiki_name, - arguments.admin_name - ], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, - env=dict(os.environ, PERL_UNICODE='AS')) - outs, errs = proc.communicate(input=pw_bytes + b'\n' + pw_bytes) - print(outs) - print(errs) - - -def subcommand_create_blog(arguments): - """Create a blog.""" - pw_bytes = sys.stdin.read().encode() - proc = subprocess.Popen([ - 'ikiwiki', '-setup', SETUP_BLOG, arguments.blog_name, - arguments.admin_name - ], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, - env=dict(os.environ, PERL_UNICODE='AS')) - outs, errs = proc.communicate(input=pw_bytes + b'\n' + pw_bytes) - print(outs) - print(errs) - - -def subcommand_delete(arguments): - """Delete a wiki or blog.""" - html_folder = os.path.join(SITE_PATH, arguments.name) - wiki_folder = os.path.join(WIKI_PATH, arguments.name) - - if not (_is_safe_path(SITE_PATH, html_folder) - and _is_safe_path(WIKI_PATH, wiki_folder)): - print('Error: {0} is not a correct name.'.format(arguments.name)) - exit(1) - - try: - shutil.rmtree(html_folder) - shutil.rmtree(wiki_folder) - shutil.rmtree(wiki_folder + '.git') - os.remove(wiki_folder + '.setup') - print('Deleted {0}'.format(arguments.name)) - except FileNotFoundError: - print('Error: {0} not found.'.format(arguments.name)) - exit(1) - - -def setup(): - """Write Apache configuration and wiki/blog setup scripts.""" - if not os.path.exists(SITE_PATH): - os.makedirs(SITE_PATH) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/ikiwiki/__init__.py b/plinth/modules/ikiwiki/__init__.py index f237a6657..72ab46354 100644 --- a/plinth/modules/ikiwiki/__init__.py +++ b/plinth/modules/ikiwiki/__init__.py @@ -1,12 +1,9 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure ikiwiki. -""" +"""FreedomBox app to configure ikiwiki.""" from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.modules.apache.components import Webserver @@ -16,7 +13,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('ikiwiki is a simple wiki and blog application. It supports ' @@ -100,9 +97,8 @@ class IkiwikiApp(app_module.App): component.remove() # Remove from global list. def refresh_sites(self): - """Refresh blog and wiki list""" - sites = actions.run('ikiwiki', ['get-sites']).split('\n') - sites = [name.split(' ', 1) for name in sites if name != ''] + """Refresh blog and wiki list.""" + sites = privileged.get_sites() for site in sites: if not 'shortcut-ikiwiki-' + site[0] in self.components: @@ -113,5 +109,5 @@ class IkiwikiApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('ikiwiki', ['setup']) + privileged.setup() self.enable() diff --git a/plinth/modules/ikiwiki/privileged.py b/plinth/modules/ikiwiki/privileged.py new file mode 100644 index 000000000..2b61e9e5c --- /dev/null +++ b/plinth/modules/ikiwiki/privileged.py @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure ikiwiki.""" + +import os +import re +import shutil +import subprocess +from typing import Tuple + +from plinth.actions import privileged + +SETUP_WIKI = '/etc/ikiwiki/plinth-wiki.setup' +SETUP_BLOG = '/etc/ikiwiki/plinth-blog.setup' +SITE_PATH = '/var/www/ikiwiki' +WIKI_PATH = '/var/lib/ikiwiki' + + +def _is_safe_path(basedir, path): + """Return whether a path is safe.""" + return os.path.realpath(path).startswith(basedir) + + +@privileged +def setup(): + """Write Apache configuration and wiki/blog setup scripts.""" + if not os.path.exists(SITE_PATH): + os.makedirs(SITE_PATH) + + +def _get_title(site): + """Get blog or wiki title.""" + try: + with open(os.path.join(SITE_PATH, site, 'index.html'), + encoding='utf-8') as index_file: + match = re.search(r'(.*)', index_file.read()) + if match: + return match[1] + except FileNotFoundError: + pass + + return site + + +@privileged +def get_sites() -> list[Tuple[str, str]]: + """Get wikis and blogs.""" + sites = [] + if os.path.exists(SITE_PATH): + for site in os.listdir(SITE_PATH): + if not os.path.isdir(os.path.join(SITE_PATH, site)): + continue + + title = _get_title(site) + sites.append((site, title)) + + return sites + + +@privileged +def create_wiki(wiki_name: str, admin_name: str, admin_password: str): + """Create a wiki.""" + pw_bytes = admin_password.encode() + input_ = pw_bytes + b'\n' + pw_bytes + subprocess.run(['ikiwiki', '-setup', SETUP_WIKI, wiki_name, admin_name], + stdout=subprocess.PIPE, input=input_, + stderr=subprocess.PIPE, + env=dict(os.environ, PERL_UNICODE='AS'), check=True) + + +@privileged +def create_blog(blog_name: str, admin_name: str, admin_password: str): + """Create a blog.""" + pw_bytes = admin_password.encode() + input_ = pw_bytes + b'\n' + pw_bytes + subprocess.run(['ikiwiki', '-setup', SETUP_BLOG, blog_name, admin_name], + stdout=subprocess.PIPE, input=input_, + stderr=subprocess.PIPE, env=dict(os.environ, + PERL_UNICODE='AS')) + + +@privileged +def delete(name: str): + """Delete a wiki or blog.""" + html_folder = os.path.join(SITE_PATH, name) + wiki_folder = os.path.join(WIKI_PATH, name) + + if not (_is_safe_path(SITE_PATH, html_folder) + and _is_safe_path(WIKI_PATH, wiki_folder)): + raise ValueError( + 'Error: {0} is not a correct wiki/blog name.'.format(name)) + + try: + shutil.rmtree(html_folder) + shutil.rmtree(wiki_folder) + shutil.rmtree(wiki_folder + '.git') + os.remove(wiki_folder + '.setup') + except FileNotFoundError: + raise RuntimeError('Unable to delete wiki/blog') diff --git a/plinth/modules/ikiwiki/views.py b/plinth/modules/ikiwiki/views.py index b7f7c4e20..4635cae8a 100644 --- a/plinth/modules/ikiwiki/views.py +++ b/plinth/modules/ikiwiki/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring ikiwiki. -""" +"""FreedomBox app for configuring ikiwiki.""" from django.contrib import messages from django.shortcuts import redirect @@ -9,10 +7,10 @@ from django.template.response import TemplateResponse from django.urls import reverse_lazy from django.utils.translation import gettext as _ -from plinth import actions from plinth import app as app_module from plinth import views +from . import privileged from .forms import IkiwikiCreateForm @@ -67,12 +65,9 @@ def create(request): def _create_wiki(request, name, admin_name, admin_password): """Create wiki.""" try: - actions.superuser_run( - 'ikiwiki', - ['create-wiki', '--wiki_name', name, '--admin_name', admin_name], - input=admin_password.encode()) + privileged.create_wiki(name, admin_name, admin_password) messages.success(request, _('Created wiki {name}.').format(name=name)) - except actions.ActionError as error: + except Exception as error: messages.error(request, _('Could not create wiki: {error}').format(error=error)) @@ -80,12 +75,9 @@ def _create_wiki(request, name, admin_name, admin_password): def _create_blog(request, name, admin_name, admin_password): """Create blog.""" try: - actions.superuser_run( - 'ikiwiki', - ['create-blog', '--blog_name', name, '--admin_name', admin_name], - input=admin_password.encode()) + privileged.create_blog(name, admin_name, admin_password) messages.success(request, _('Created blog {name}.').format(name=name)) - except actions.ActionError as error: + except Exception as error: messages.error(request, _('Could not create blog: {error}').format(error=error)) @@ -100,11 +92,11 @@ def delete(request, name): title = app.components['shortcut-ikiwiki-' + name].name if request.method == 'POST': try: - actions.superuser_run('ikiwiki', ['delete', '--name', name]) + privileged.delete(name) app.remove_shortcut(name) messages.success(request, _('{title} deleted.').format(title=title)) - except actions.ActionError as error: + except Exception as error: messages.error( request, _('Could not delete {title}: {error}').format( From 02ef750442d4d4bc85c9df161c39e0763c29e3a8 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 11:55:26 -0700 Subject: [PATCH 34/90] infinoted: Use privileged decorator for actions Tests: - Functional tests work - Initial setup succeeds - infinoted user/group is added to the system - systemd service is created and service is running after install - Directories /var/lib/infinoted, /etc/infinoted and /var/lib/infinoted/sync are created with infinoted as owner and group. - Certificates /etc/infinoted/infinoted-{cert,key}.pem are created with infinoted as owner and group. - Enabling/disabling works and enables/disables the service - Gobby is able to connect to the server and create a document Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/infinoted/__init__.py | 5 ++- .../modules/infinoted/privileged.py | 34 +++---------------- 2 files changed, 6 insertions(+), 33 deletions(-) rename actions/infinoted => plinth/modules/infinoted/privileged.py (85%) mode change 100755 => 100644 diff --git a/plinth/modules/infinoted/__init__.py b/plinth/modules/infinoted/__init__.py index 315b18161..e70d684f6 100644 --- a/plinth/modules/infinoted/__init__.py +++ b/plinth/modules/infinoted/__init__.py @@ -6,7 +6,6 @@ FreedomBox app for infinoted. from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -15,7 +14,7 @@ from plinth.modules.firewall.components import Firewall from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('infinoted is a server for Gobby, a collaborative text editor.'), @@ -77,5 +76,5 @@ class InfinotedApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('infinoted', ['setup']) + privileged.setup() self.enable() diff --git a/actions/infinoted b/plinth/modules/infinoted/privileged.py old mode 100755 new mode 100644 similarity index 85% rename from actions/infinoted rename to plinth/modules/infinoted/privileged.py index aef33246a..9675030a1 --- a/actions/infinoted +++ b/plinth/modules/infinoted/privileged.py @@ -1,10 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for infinoted. -""" +"""Configure infinoted.""" -import argparse import grp import os import pwd @@ -13,6 +9,7 @@ import subprocess import time from plinth import action_utils +from plinth.actions import privileged DATA_DIR = '/var/lib/infinoted' KEY_DIR = '/etc/infinoted' @@ -103,17 +100,6 @@ WantedBy=multi-user.target ''' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Configure infinoted after install') - - subparsers.required = True - return parser.parse_args() - - def _kill_daemon(): """Try to kill the infinoted daemon for upto 5 minutes.""" end_time = time.time() + 300 @@ -127,7 +113,8 @@ def _kill_daemon(): time.sleep(1) -def subcommand_setup(_): +@privileged +def setup(): """Configure infinoted after install.""" if not os.path.isfile(CONF_PATH): with open(CONF_PATH, 'w', encoding='utf-8') as file_handle: @@ -180,16 +167,3 @@ def subcommand_setup(_): group='infinoted') action_utils.service_enable('infinoted') - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() From c1cf5699c20f0f3405ba6db609133465e7f76e36 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 2 Sep 2022 16:53:17 -0700 Subject: [PATCH 35/90] letsencrypt: Use privileged decorator for actions Tests: - DONE: Initial setup works - DONE: Certificate events on FreedomBox startup work - DONE: Basic operations work: obtain, revoke, delete - DONE: Status of certificates is shown properly - DONE: Domain add/remove hooks work, errors are handled - Not tested: Removing old hooks - DONE: Errors are shown properly on failure: revoke, obtain, reobtain, delete Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/letsencrypt | 496 +----------------- plinth/modules/letsencrypt/__init__.py | 35 +- plinth/modules/letsencrypt/components.py | 33 +- plinth/modules/letsencrypt/privileged.py | 359 +++++++++++++ .../letsencrypt/tests/test_components.py | 217 ++++---- plinth/modules/letsencrypt/views.py | 17 +- 6 files changed, 510 insertions(+), 647 deletions(-) create mode 100644 plinth/modules/letsencrypt/privileged.py diff --git a/actions/letsencrypt b/actions/letsencrypt index ed9fb04fc..cf0190e04 100755 --- a/actions/letsencrypt +++ b/actions/letsencrypt @@ -1,493 +1,9 @@ #!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later +"""Legacy configuration helper for Let's Encrypt, kept for compatibility. + +LE configuration in the earlier implementation used to call into this script +with the sub-commands 'run-pre-hooks', 'run-renew-hooks' and 'run-post-hooks'. +This action script now allows for any arbitrary sub-command to be called and +does nothing. It can be removed after the release of Debian 12 (bookworm). """ -Configuration helper for Let's Encrypt. -""" - -import argparse -import filecmp -import glob -import importlib -import inspect -import json -import os -import pathlib -import re -import shutil -import subprocess -import sys - -import configobj - -from plinth import action_utils -from plinth import app as app_module -from plinth import cfg -from plinth.modules import letsencrypt as le -from plinth.modules.letsencrypt.components import LetsEncrypt - -TEST_MODE = False -LE_DIRECTORY = '/etc/letsencrypt/' -ETC_SSL_DIRECTORY = '/etc/ssl/' -RENEWAL_DIRECTORY = '/etc/letsencrypt/renewal/' -AUTHENTICATOR = 'webroot' -WEB_ROOT_PATH = '/var/www/html' -APACHE_PREFIX = '/etc/apache2/sites-available/' -APACHE_CONFIGURATION = ''' -Use FreedomBoxTLSSiteMacro {domain} -''' - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - setup_parser = subparsers.add_parser( - 'setup', help='Run any setup/upgrade activities.') - setup_parser.add_argument( - '--old-version', type=int, required=True, - help='Version number being upgraded from or None if setting up first ' - 'time.') - - subparsers.add_parser('get-status', - help='Return the status of configured domains.') - subparser = subparsers.add_parser( - 'get-modified-time', - help='Return the modified time for a certificate.') - subparser.add_argument('--domain', required=True, - help='Domain name to get modified time for') - revoke_parser = subparsers.add_parser( - 'revoke', help='Revoke certificate of a domain and disable website.') - revoke_parser.add_argument('--domain', required=True, - help='Domain name to revoke certificate for') - obtain_parser = subparsers.add_parser( - 'obtain', help='Obtain certificate for a domain and setup website.') - obtain_parser.add_argument('--domain', required=True, - help='Domain name to obtain certificate for') - delete_parser = subparsers.add_parser( - 'delete', help='Delete certificate for a domain and disable website.') - delete_parser.add_argument('--domain', required=True, - help='Domain name to delete certificate of') - - subparser = subparsers.add_parser( - 'copy-certificate', - help='Copy LE certificate to a daemon\'s directory') - subparser.add_argument('--managing-app', required=True, - help='App needing the certificate') - subparser.add_argument('--user-owner', required=True, - help='User who should own the certificate') - subparser.add_argument('--group-owner', required=True, - help='Group that should own the certificate') - subparser.add_argument('--source-private-key-path', required=True, - help='Path to the source private key') - subparser.add_argument( - '--source-certificate-path', required=True, - help='Path to the source certificate with public key') - subparser.add_argument('--private-key-path', required=True, - help='Path to the private key') - subparser.add_argument('--certificate-path', required=True, - help='Path to the certificate with public key') - - subparser = subparsers.add_parser( - 'compare-certificate', - help='Compare LE certificate to one in daemon\'s directory') - subparser.add_argument('--managing-app', required=True, - help='App needing the certificate') - subparser.add_argument('--source-private-key-path', required=True, - help='Path to the source private key') - subparser.add_argument( - '--source-certificate-path', required=True, - help='Path to the source certificate with public key') - subparser.add_argument('--private-key-path', required=True, - help='Path to the private key') - subparser.add_argument('--certificate-path', required=True, - help='Path to the certificate with public key') - - help_hooks = 'Does nothing, kept for compatibility.' - subparser = subparsers.add_parser('run_pre_hooks', help=help_hooks) - subparser.add_argument('--domain') - subparser.add_argument('--modules', nargs='+', default=[]) - - subparser = subparsers.add_parser('run_renew_hooks', help=help_hooks) - subparser.add_argument('--domain') - subparser.add_argument('--modules', nargs='+', default=[]) - - subparser = subparsers.add_parser('run_post_hooks', help=help_hooks) - subparser.add_argument('--domain') - subparser.add_argument('--modules', nargs='+', default=[]) - - subparsers.required = True - return parser.parse_args() - - -def get_certificate_expiry(domain): - """Return the expiry date of a certificate.""" - certificate_file = os.path.join(le.LIVE_DIRECTORY, domain, 'cert.pem') - output = subprocess.check_output( - ['openssl', 'x509', '-enddate', '-noout', '-in', certificate_file]) - return output.decode().strip().split('=')[1] - - -def get_modified_time(domain): - """Return the last modified time of a certificate.""" - certificate_file = pathlib.Path(le.LIVE_DIRECTORY) / domain / 'cert.pem' - return int(certificate_file.stat().st_mtime) - - -def get_validity_status(domain): - """Return validity status of a certificate, e.g. valid, revoked, expired""" - output = subprocess.check_output(['certbot', 'certificates', '-d', domain]) - output = output.decode(sys.stdout.encoding) - - match = re.search(r'INVALID: (.*)\)', output) - if match is not None: - validity = match.group(1).lower() - elif re.search('VALID', output) is not None: - validity = 'valid' - else: - validity = 'unknown' - - return validity - - -def get_status(): - """ - Return Python dictionary of currently configured domains. - Should be run as root, otherwise might yield a wrong, empty answer. - """ - try: - domains = os.listdir(le.LIVE_DIRECTORY) - except OSError: - domains = [] - - domains = [ - domain for domain in domains - if os.path.isdir(os.path.join(le.LIVE_DIRECTORY, domain)) - ] - - domain_status = {} - for domain in domains: - domain_status[domain] = { - 'certificate_available': - True, - 'expiry_date': - get_certificate_expiry(domain), - 'web_enabled': - action_utils.webserver_is_enabled(domain, kind='site'), - 'validity': - get_validity_status(domain), - 'lineage': - str(pathlib.Path(le.LIVE_DIRECTORY) / domain), - 'modified_time': - get_modified_time(domain) - } - return domain_status - - -def subcommand_setup(arguments): - """Upgrade old site configuration to new macro based style. - - Nothing to do for first time setup and for newer versions. - """ - if arguments.old_version == 2: - _remove_old_hooks() - return - - if arguments.old_version != 1: - return - - domain_status = get_status() - with action_utils.WebserverChange() as webserver_change: - for domain in domain_status: - setup_webserver_config(domain, webserver_change) - - -def subcommand_get_status(_): - """Print a JSON dictionary of currently configured domains.""" - domain_status = get_status() - print(json.dumps({'domains': domain_status})) - - -def subcommand_get_modified_time(arguments): - """Print the modified time of a certificate as integer.""" - print(get_modified_time(arguments.domain)) - - -def subcommand_revoke(arguments): - """Disable a domain and revoke the certificate.""" - domain = arguments.domain - - cert_path = pathlib.Path(le.LIVE_DIRECTORY) / domain / 'cert.pem' - if cert_path.exists(): - command = [ - 'certbot', 'revoke', '--non-interactive', '--domain', domain, - '--cert-path', cert_path - ] - if TEST_MODE: - command.append('--staging') - - process = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - _, stderr = process.communicate() - if process.returncode: - print(stderr.decode(), file=sys.stderr) - sys.exit(1) - - action_utils.webserver_disable(domain, kind='site') - - -def subcommand_obtain(arguments): - """Obtain a certificate for a domain and setup website.""" - domain = arguments.domain - - command = [ - 'certbot', 'certonly', '--non-interactive', '--text', '--agree-tos', - '--register-unsafely-without-email', '--domain', arguments.domain, - '--authenticator', AUTHENTICATOR, '--webroot-path', WEB_ROOT_PATH, - '--renew-by-default' - ] - if TEST_MODE: - command.append('--staging') - - process = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - _, stderr = process.communicate() - if process.returncode: - print(stderr.decode(), file=sys.stderr) - sys.exit(1) - - with action_utils.WebserverChange() as webserver_change: - setup_webserver_config(domain, webserver_change) - - -def _remove_old_hooks(): - """Remove old style renewal hooks from individual configuration files. - - This has been replaced with global hooks by adding script files in - directory /etc/letsencrypt/renewal-hooks/{pre,post,deploy}/. - - """ - for file_path in glob.glob(RENEWAL_DIRECTORY + '*.conf'): - try: - _remove_old_hooks_from_file(file_path) - except Exception as exception: - print('Error removing hooks from file:', file_path, exception) - - -def _remove_old_hooks_from_file(file_path): - """Remove old style hooks from a single configuration file.""" - config = configobj.ConfigObj(file_path) - edited = False - for line in config.initial_comment: - if 'edited by plinth' in line.lower(): - edited = True - - if not edited: - return - - config.initial_comment = [ - line for line in config.initial_comment - if 'edited by plinth' not in line.lower() - ] - - if 'pre_hook' in config['renewalparams']: - del config['renewalparams']['pre_hook'] - - if 'renew_hook' in config['renewalparams']: - del config['renewalparams']['renew_hook'] - - if 'post_hook' in config['renewalparams']: - del config['renewalparams']['post_hook'] - - config.write() - - -def subcommand_copy_certificate(arguments): - """Copy certificate from LE directory to daemon's directory. - - Set ownership and permissions as requested needed by the daemon. - - """ - source_private_key_path = pathlib.Path( - arguments.source_private_key_path).resolve() - _assert_source_directory(source_private_key_path) - source_certificate_path = pathlib.Path( - arguments.source_certificate_path).resolve() - _assert_source_directory(source_certificate_path) - - private_key_path = pathlib.Path(arguments.private_key_path).resolve() - _assert_managed_path(arguments.managing_app, private_key_path) - certificate_path = pathlib.Path(arguments.certificate_path).resolve() - _assert_managed_path(arguments.managing_app, certificate_path) - - # Create directories, owned by root - private_key_path.parent.mkdir(mode=0o755, parents=True, exist_ok=True) - certificate_path.parent.mkdir(mode=0o755, parents=True, exist_ok=True) - - # Private key is only accessible to the user owner - old_mask = os.umask(0o177) - shutil.copyfile(source_private_key_path, private_key_path) - - if certificate_path != private_key_path: - # Certificate is only writable by the user owner - os.umask(0o133) - shutil.copyfile(source_certificate_path, certificate_path) - else: - # If private key and certificate are the same file, append one after - # the other. - source_certificate = source_certificate_path.read_bytes() - with private_key_path.open(mode='a+b') as file_handle: - file_handle.write(source_certificate) - - os.umask(old_mask) - - shutil.chown(certificate_path, user=arguments.user_owner, - group=arguments.group_owner) - shutil.chown(private_key_path, user=arguments.user_owner, - group=arguments.group_owner) - - -def subcommand_compare_certificate(arguments): - """Compare LE certificate with an app certificate.""" - source_private_key_path = pathlib.Path(arguments.source_private_key_path) - source_certificate_path = pathlib.Path(arguments.source_certificate_path) - _assert_source_directory(source_private_key_path) - _assert_source_directory(source_certificate_path) - - private_key_path = pathlib.Path(arguments.private_key_path) - certificate_path = pathlib.Path(arguments.certificate_path) - _assert_managed_path(arguments.managing_app, private_key_path) - _assert_managed_path(arguments.managing_app, certificate_path) - - result = False - try: - if filecmp.cmp(source_certificate_path, certificate_path) and \ - filecmp.cmp(source_private_key_path, private_key_path): - result = True - except FileNotFoundError: - result = False - - print(json.dumps({'result': result})) - - -def _assert_source_directory(path): - """Assert that a path is a valid source of a certificates.""" - assert (str(path).startswith(LE_DIRECTORY) - or str(path).startswith(ETC_SSL_DIRECTORY)) - - -def _get_managed_path(path): - """Return the managed path given a certificate path.""" - if '{domain}' in path: - return pathlib.Path(path.partition('{domain}')[0]) - - return pathlib.Path(path).parent - - -def _assert_managed_path(module, path): - """Check that path is in fact managed by module.""" - cfg.read() - module_file = pathlib.Path(cfg.config_dir) / 'modules-enabled' / module - module_path = module_file.read_text().strip() - - module = importlib.import_module(module_path) - module_classes = inspect.getmembers(module, inspect.isclass) - app_classes = [ - cls[1] for cls in module_classes if issubclass(cls[1], app_module.App) - ] - - managed_paths = [] - for cls in app_classes: - app = cls() - components = app.get_components_of_type(LetsEncrypt) - for component in components: - if component.private_key_path: - managed_paths.append( - _get_managed_path(component.private_key_path)) - if component.certificate_path: - managed_paths.append( - _get_managed_path(component.certificate_path)) - - assert set(path.parents).intersection(set(managed_paths)) - - -def subcommand_run_pre_hooks(_): - """Do nothing, kept for legacy LE configuration. - - If new version of Plinth is deployed and before it can update the Let's - Encrypt configuration and remove these old hooks, if a renew operation is - run, then we don't want it to exit with non-zero error code because this - hook could not be run. - - Remove at some point in the future. - - """ - - -def subcommand_run_renew_hooks(_): - """Do nothing, kept for legacy LE configuration. - - If new version of Plinth is deployed and before it can update the Let's - Encrypt configuration and remove these old hooks, if a renew operation is - run, then we don't want it to exit with non-zero error code because this - hook could not be run. - - Remove at some point in the future. - - """ - - -def subcommand_run_post_hooks(_): - """Do nothing, kept for legacy LE configuration. - - If new version of Plinth is deployed and before it can update the Let's - Encrypt configuration and remove these old hooks, if a renew operation is - run, then we don't want it to exit with non-zero error code because this - hook could not be run. - - Remove at some point in the future. - - """ - - -def subcommand_delete(arguments): - """Disable a domain and delete the certificate.""" - domain = arguments.domain - command = ['certbot', 'delete', '--non-interactive', '--cert-name', domain] - process = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - _, stderr = process.communicate() - if process.returncode: - print(stderr.decode(), file=sys.stderr) - sys.exit(1) - - action_utils.webserver_disable(domain, kind='site') - - -def setup_webserver_config(domain, webserver_change): - """Create SSL web server configuration for a domain. - - Do so only if there is no configuration existing. - """ - file_name = os.path.join(APACHE_PREFIX, domain + '.conf') - if os.path.isfile(file_name): - os.rename(file_name, file_name + '.fbx-bak') - - with open(file_name, 'w', encoding='utf-8') as file_handle: - file_handle.write(APACHE_CONFIGURATION.format(domain=domain)) - - webserver_change.enable('freedombox-tls-site-macro', kind='config') - webserver_change.enable(domain, kind='site') - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/letsencrypt/__init__.py b/plinth/modules/letsencrypt/__init__.py index 76b067e10..3718e67c9 100644 --- a/plinth/modules/letsencrypt/__init__.py +++ b/plinth/modules/letsencrypt/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for using Let's Encrypt. -""" +"""FreedomBox app for using Let's Encrypt.""" import json import logging @@ -9,10 +7,8 @@ import pathlib from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, menu -from plinth.errors import ActionError from plinth.modules import names from plinth.modules.apache.components import diagnose_url from plinth.modules.backups.components import BackupRestore @@ -21,7 +17,7 @@ from plinth.package import Packages from plinth.signals import domain_added, domain_removed, post_app_loading from plinth.utils import format_lazy -from . import components, manifest +from . import components, manifest, privileged _description = [ format_lazy( @@ -102,14 +98,12 @@ class LetsEncryptApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('letsencrypt', - ['setup', '--old-version', - str(old_version)]) + privileged.setup(old_version) def certificate_obtain(domain): """Obtain a certificate for a domain and notify handlers.""" - actions.superuser_run('letsencrypt', ['obtain', '--domain', domain]) + privileged.obtain(domain) components.on_certificate_event('obtained', [domain], None) @@ -124,7 +118,7 @@ def certificate_reobtain(domain): trigger obtain event (LE will trigger a renewal event). """ - actions.superuser_run('letsencrypt', ['obtain', '--domain', domain]) + privileged.obtain(domain) def certificate_revoke(domain, really_revoke=True): @@ -138,20 +132,20 @@ def certificate_revoke(domain, really_revoke=True): obtaining certificates on the Let's Encrypt servers). """ if really_revoke: - actions.superuser_run('letsencrypt', ['revoke', '--domain', domain]) + privileged.revoke(domain) components.on_certificate_event('revoked', [domain], None) def certificate_delete(domain): """Delete a certificate for a domain and notify handlers.""" - actions.superuser_run('letsencrypt', ['delete', '--domain', domain]) + privileged.delete(domain) components.on_certificate_event('deleted', [domain], None) def on_domain_added(sender, domain_type='', name='', description='', services=None, **kwargs): - """Obtain a certificate for the new domain""" + """Obtain a certificate for the new domain.""" if not DomainType.get(domain_type).can_have_certificate: return False @@ -167,12 +161,12 @@ def on_domain_added(sender, domain_type='', name='', description='', logger.info('Obtaining certificate for %s', name) certificate_obtain(name) return True - except ActionError: + except Exception: return False def on_domain_removed(sender, domain_type, name='', **kwargs): - """Revoke Let's Encrypt certificate for the removed domain""" + """Revoke Let's Encrypt certificate for the removed domain.""" if not DomainType.get(domain_type).can_have_certificate: return False @@ -181,7 +175,7 @@ def on_domain_removed(sender, domain_type, name='', **kwargs): logger.info('Revoking certificate for %s', name) certificate_revoke(name, really_revoke=False) return True - except ActionError as exception: + except Exception as exception: logger.warning('Failed to revoke certificate for %s: %s', name, exception.args[2]) return False @@ -189,8 +183,7 @@ def on_domain_removed(sender, domain_type, name='', **kwargs): def get_status(): """Get the current settings.""" - status = actions.superuser_run('letsencrypt', ['get-status']) - status = json.loads(status) + status = privileged.get_status() for domain in names.components.DomainName.list(): if domain.domain_type.can_have_certificate: @@ -247,9 +240,7 @@ def certificate_get_last_seen_modified_time(lineage): def certificate_set_last_seen_modified_time(lineage): """Write to store a certificate's last seen expiry date.""" lineage = pathlib.Path(lineage) - output = actions.superuser_run( - 'letsencrypt', ['get-modified-time', '--domain', lineage.name]) - modified_time = int(output) + modified_time = privileged.get_modified_time(lineage.name) from plinth import kvstore info = kvstore.get_default('letsencrypt_certificate_info', '{}') diff --git a/plinth/modules/letsencrypt/components.py b/plinth/modules/letsencrypt/components.py index e6f1a29ac..5fa760598 100644 --- a/plinth/modules/letsencrypt/components.py +++ b/plinth/modules/letsencrypt/components.py @@ -1,9 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -App component for other apps to use handle Let's Encrypt certificates. -""" +"""App component for other apps to use handle Let's Encrypt certificates.""" -import json import logging import pathlib import threading @@ -11,6 +8,8 @@ import threading from plinth import actions, app from plinth.modules.names.components import DomainName +from . import privileged + logger = logging.getLogger(__name__) @@ -327,14 +326,11 @@ class LetsEncrypt(app.FollowerComponent): source_certificate_path, private_key_path, certificate_path): """Copy certificate for a single domain.""" - actions.superuser_run('letsencrypt', [ - 'copy-certificate', '--managing-app', self.managing_app, - '--user-owner', self.user_owner, '--group-owner', self.group_owner, - '--source-private-key-path', - str(source_private_key_path), '--source-certificate-path', - str(source_certificate_path), '--private-key-path', - private_key_path, '--certificate-path', certificate_path - ]) + privileged.copy_certificate(self.managing_app, + str(source_private_key_path), + str(source_certificate_path), + private_key_path, certificate_path, + self.user_owner, self.group_owner) def _compare_certificate(self, domain, lineage): """Compare LE certificate with app certificate.""" @@ -342,14 +338,11 @@ class LetsEncrypt(app.FollowerComponent): source_certificate_path = pathlib.Path(lineage) / 'fullchain.pem' private_key_path = self.private_key_path.format(domain=domain) certificate_path = self.certificate_path.format(domain=domain) - output = actions.superuser_run('letsencrypt', [ - 'compare-certificate', '--managing-app', self.managing_app, - '--source-private-key-path', - str(source_private_key_path), '--source-certificate-path', - str(source_certificate_path), '--private-key-path', - private_key_path, '--certificate-path', certificate_path - ]) - return json.loads(output)['result'] + return privileged.compare_certificate(self.managing_app, + str(source_private_key_path), + str(source_certificate_path), + private_key_path, + certificate_path) def on_certificate_event(event, domains, lineage): diff --git a/plinth/modules/letsencrypt/privileged.py b/plinth/modules/letsencrypt/privileged.py new file mode 100644 index 000000000..d77e9e29a --- /dev/null +++ b/plinth/modules/letsencrypt/privileged.py @@ -0,0 +1,359 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure Let's Encrypt.""" + +import filecmp +import glob +import importlib +import inspect +import os +import pathlib +import re +import shutil +import subprocess +import sys +from typing import Any + +import configobj + +from plinth import action_utils +from plinth import app as app_module +from plinth import cfg +from plinth.actions import privileged +from plinth.modules import letsencrypt as le + +TEST_MODE = False +LE_DIRECTORY = '/etc/letsencrypt/' +ETC_SSL_DIRECTORY = '/etc/ssl/' +RENEWAL_DIRECTORY = '/etc/letsencrypt/renewal/' +AUTHENTICATOR = 'webroot' +WEB_ROOT_PATH = '/var/www/html' +APACHE_PREFIX = '/etc/apache2/sites-available/' +APACHE_CONFIGURATION = ''' +Use FreedomBoxTLSSiteMacro {domain} +''' + + +def _get_certificate_expiry(domain: str) -> str: + """Return the expiry date of a certificate.""" + certificate_file = os.path.join(le.LIVE_DIRECTORY, domain, 'cert.pem') + output = subprocess.check_output( + ['openssl', 'x509', '-enddate', '-noout', '-in', certificate_file]) + return output.decode().strip().split('=')[1] + + +def _get_modified_time(domain: str) -> int: + """Return the last modified time of a certificate.""" + certificate_file = pathlib.Path(le.LIVE_DIRECTORY) / domain / 'cert.pem' + return int(certificate_file.stat().st_mtime) + + +def _get_validity_status(domain: str) -> str: + """Return validity status of a certificate; valid, revoked, expired.""" + output = subprocess.check_output(['certbot', 'certificates', '-d', domain]) + line = output.decode(sys.stdout.encoding) + + match = re.search(r'INVALID: (.*)\)', line) + if match is not None: + validity = match.group(1).lower() + elif re.search('VALID', line) is not None: + validity = 'valid' + else: + validity = 'unknown' + + return validity + + +def _get_status() -> dict[str, Any]: + """Return Python dictionary of currently configured domains. + + Should be run as root, otherwise might yield a wrong, empty answer. + """ + try: + domains = os.listdir(le.LIVE_DIRECTORY) + except OSError: + domains = [] + + domains = [ + domain for domain in domains + if os.path.isdir(os.path.join(le.LIVE_DIRECTORY, domain)) + ] + + domain_status = {} + for domain in domains: + domain_status[domain] = { + 'certificate_available': + True, + 'expiry_date': + _get_certificate_expiry(domain), + 'web_enabled': + action_utils.webserver_is_enabled(domain, kind='site'), + 'validity': + _get_validity_status(domain), + 'lineage': + str(pathlib.Path(le.LIVE_DIRECTORY) / domain), + 'modified_time': + _get_modified_time(domain) + } + return domain_status + + +@privileged +def setup(old_version: int): + """Upgrade old site configuration to new macro based style. + + Nothing to do for first time setup and for newer versions. + """ + if old_version == 2: + _remove_old_hooks() + return + + if old_version != 1: + return + + domain_status = _get_status() + with action_utils.WebserverChange() as webserver_change: + for domain in domain_status: + _setup_webserver_config(domain, webserver_change) + + +@privileged +def get_status() -> dict[str, Any]: + """Return a dictionary of currently configured domains.""" + domain_status = _get_status() + return {'domains': domain_status} + + +@privileged +def get_modified_time(domain: str) -> int: + """Return the modified time of a certificate as integer.""" + return _get_modified_time(domain) + + +@privileged +def revoke(domain: str): + """Disable a domain and revoke the certificate.""" + cert_path = pathlib.Path(le.LIVE_DIRECTORY) / domain / 'cert.pem' + if cert_path.exists(): + command = [ + 'certbot', 'revoke', '--non-interactive', '--domain', domain, + '--cert-path', + str(cert_path) + ] + if TEST_MODE: + command.append('--staging') + + process = subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + _, stderr = process.communicate() + if process.returncode: + raise RuntimeError('Error revoking certificate: {error}'.format( + error=stderr.decode())) + + action_utils.webserver_disable(domain, kind='site') + + +@privileged +def obtain(domain: str): + """Obtain a certificate for a domain and setup website.""" + command = [ + 'certbot', 'certonly', '--non-interactive', '--text', '--agree-tos', + '--register-unsafely-without-email', '--domain', domain, + '--authenticator', AUTHENTICATOR, '--webroot-path', WEB_ROOT_PATH, + '--renew-by-default' + ] + if TEST_MODE: + command.append('--staging') + + process = subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + _, stderr = process.communicate() + if process.returncode: + raise RuntimeError('Error obtaining certificate: {error}'.format( + error=stderr.decode())) + + with action_utils.WebserverChange() as webserver_change: + _setup_webserver_config(domain, webserver_change) + + +def _remove_old_hooks(): + """Remove old style renewal hooks from individual configuration files. + + This has been replaced with global hooks by adding script files in + directory /etc/letsencrypt/renewal-hooks/{pre,post,deploy}/. + """ + for file_path in glob.glob(RENEWAL_DIRECTORY + '*.conf'): + try: + _remove_old_hooks_from_file(file_path) + except Exception as exception: + print('Error removing hooks from file:', file_path, exception) + + +def _remove_old_hooks_from_file(file_path: str): + """Remove old style hooks from a single configuration file.""" + config = configobj.ConfigObj(file_path) + edited = False + for line in config.initial_comment: + if 'edited by plinth' in line.lower(): + edited = True + + if not edited: + return + + config.initial_comment = [ + line for line in config.initial_comment + if 'edited by plinth' not in line.lower() + ] + + if 'pre_hook' in config['renewalparams']: + del config['renewalparams']['pre_hook'] + + if 'renew_hook' in config['renewalparams']: + del config['renewalparams']['renew_hook'] + + if 'post_hook' in config['renewalparams']: + del config['renewalparams']['post_hook'] + + config.write() + + +@privileged +def copy_certificate(managing_app: str, source_private_key: str, + source_certificate: str, private_key: str, + certificate: str, user_owner: str, group_owner: str): + """Copy certificate from LE directory to daemon's directory. + + Set ownership and permissions as requested needed by the daemon. + + """ + source_private_key_path = pathlib.Path(source_private_key).resolve() + _assert_source_directory(source_private_key_path) + source_certificate_path = pathlib.Path(source_certificate).resolve() + _assert_source_directory(source_certificate_path) + + private_key_path = pathlib.Path(private_key).resolve() + _assert_managed_path(managing_app, private_key_path) + certificate_path = pathlib.Path(certificate).resolve() + _assert_managed_path(managing_app, certificate_path) + + # Create directories, owned by root + private_key_path.parent.mkdir(mode=0o755, parents=True, exist_ok=True) + certificate_path.parent.mkdir(mode=0o755, parents=True, exist_ok=True) + + # Private key is only accessible to the user owner + old_mask = os.umask(0o177) + shutil.copyfile(source_private_key_path, private_key_path) + + if certificate_path != private_key_path: + # Certificate is only writable by the user owner + os.umask(0o133) + shutil.copyfile(source_certificate_path, certificate_path) + else: + # If private key and certificate are the same file, append one after + # the other. + source_certificate_bytes = source_certificate_path.read_bytes() + with private_key_path.open(mode='a+b') as file_handle: + file_handle.write(source_certificate_bytes) + + os.umask(old_mask) + + shutil.chown(certificate_path, user=user_owner, group=group_owner) + shutil.chown(private_key_path, user=user_owner, group=group_owner) + + +@privileged +def compare_certificate(managing_app: str, source_private_key: str, + source_certificate: str, private_key: str, + certificate: str) -> bool: + """Compare LE certificate with an app certificate.""" + source_private_key_path = pathlib.Path(source_private_key) + source_certificate_path = pathlib.Path(source_certificate) + _assert_source_directory(source_private_key_path) + _assert_source_directory(source_certificate_path) + + private_key_path = pathlib.Path(private_key) + certificate_path = pathlib.Path(certificate) + _assert_managed_path(managing_app, private_key) + _assert_managed_path(managing_app, certificate) + + result = False + try: + if filecmp.cmp(source_certificate_path, certificate_path) and \ + filecmp.cmp(source_private_key_path, private_key_path): + result = True + except FileNotFoundError: + result = False + + return result + + +def _assert_source_directory(path): + """Assert that a path is a valid source of a certificates.""" + assert (str(path).startswith(LE_DIRECTORY) + or str(path).startswith(ETC_SSL_DIRECTORY)) + + +def _get_managed_path(path): + """Return the managed path given a certificate path.""" + if '{domain}' in path: + return pathlib.Path(path.partition('{domain}')[0]) + + return pathlib.Path(path).parent + + +def _assert_managed_path(module, path): + """Check that path is in fact managed by module.""" + cfg.read() + module_file = pathlib.Path(cfg.config_dir) / 'modules-enabled' / module + module_path = module_file.read_text().strip() + + module = importlib.import_module(module_path) + module_classes = inspect.getmembers(module, inspect.isclass) + app_classes = [ + cls[1] for cls in module_classes if issubclass(cls[1], app_module.App) + ] + + managed_paths = [] + for cls in app_classes: + app = cls() + from plinth.modules.letsencrypt.components import LetsEncrypt + components = app.get_components_of_type(LetsEncrypt) + for component in components: + if component.private_key_path: + managed_paths.append( + _get_managed_path(component.private_key_path)) + if component.certificate_path: + managed_paths.append( + _get_managed_path(component.certificate_path)) + + if not set(path.parents).intersection(set(managed_paths)): + raise AssertionError('Not a managed path') + + +@privileged +def delete(domain: str): + """Disable a domain and delete the certificate.""" + command = ['certbot', 'delete', '--non-interactive', '--cert-name', domain] + process = subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + _, stderr = process.communicate() + if process.returncode: + raise RuntimeError('Error deleting certificate: {error}'.format( + error=stderr.decode())) + + action_utils.webserver_disable(domain, kind='site') + + +def _setup_webserver_config(domain, webserver_change): + """Create SSL web server configuration for a domain. + + Do so only if there is no configuration existing. + """ + file_name = os.path.join(APACHE_PREFIX, domain + '.conf') + if os.path.isfile(file_name): + os.rename(file_name, file_name + '.fbx-bak') + + with open(file_name, 'w', encoding='utf-8') as file_handle: + file_handle.write(APACHE_CONFIGURATION.format(domain=domain)) + + webserver_change.enable('freedombox-tls-site-macro', kind='config') + webserver_change.enable(domain, kind='site') diff --git a/plinth/modules/letsencrypt/tests/test_components.py b/plinth/modules/letsencrypt/tests/test_components.py index 942db5f0a..320c235ad 100644 --- a/plinth/modules/letsencrypt/tests/test_components.py +++ b/plinth/modules/letsencrypt/tests/test_components.py @@ -3,7 +3,6 @@ Test the Let's Encrypt component for managing certificates. """ -import json from unittest.mock import call, patch import pytest @@ -30,6 +29,29 @@ def fixture_component(): managing_app='test-app') +@pytest.fixture(name='try_restart') +def fixture_try_restart(): + """Patch and return service.try_restart privileged call.""" + with patch('plinth.privileged.service.try_restart') as try_restart: + yield try_restart + + +@pytest.fixture(name='copy_certificate') +def fixture_copy_certificate(): + """Patch and return privileged.copy_certificate call.""" + with patch('plinth.modules.letsencrypt.privileged.copy_certificate' + ) as copy_certificate: + yield copy_certificate + + +@pytest.fixture(name='compare_certificate') +def fixture_compare_certificate(): + """Patch and return privileged.compare_certificate call.""" + with patch('plinth.modules.letsencrypt.privileged.compare_certificate' + ) as compare_certificate: + yield compare_certificate + + @pytest.fixture(name='get_status') def fixture_get_status(): """Return patched letsencrypt.get_status() method.""" @@ -65,13 +87,6 @@ def fixture_domain_list(): yield domain_list -@pytest.fixture(name='superuser_run') -def fixture_superuser_run(): - """Return patched plinth.actions.superuser_run() method.""" - with patch('plinth.actions.superuser_run') as superuser_run: - yield superuser_run - - def test_init_without_arguments(): """Test that component is initialized with defaults properly.""" component = LetsEncrypt('test-component') @@ -133,13 +148,8 @@ def test_list(): assert set(LetsEncrypt.list()) == {component1, component2} -def _assert_copy_certificate_called(component, superuser_run, domains): +def _assert_copy_certificate_called(component, copy_certificate, domains): """Check that copy certificate calls have been made properly.""" - copy_calls = [ - mock_call for mock_call in superuser_run.mock_calls - if mock_call[1][0] == 'letsencrypt' - and mock_call[1][1][0] == 'copy-certificate' - ] expected_calls = [] for domain, domain_status in domains.items(): if domain_status == 'valid': @@ -153,83 +163,72 @@ def _assert_copy_certificate_called(component, superuser_run, domains): private_key_path = '/etc/test-app/{}/private.path'.format(domain) certificate_path = '/etc/test-app/{}/certificate.path'.format(domain) - expected_call = call('letsencrypt', [ - 'copy-certificate', '--managing-app', component.managing_app, - '--user-owner', component.user_owner, '--group-owner', - component.group_owner, '--source-private-key-path', - str(source_private_key_path), '--source-certificate-path', - str(source_certificate_path), '--private-key-path', - private_key_path, '--certificate-path', certificate_path - ]) + expected_call = call(component.managing_app, + str(source_private_key_path), + str(source_certificate_path), private_key_path, + certificate_path, component.user_owner, + component.group_owner) expected_calls.append(expected_call) - assert len(expected_calls) == len(copy_calls) - for expected_call in expected_calls: - print(expected_call) - print(copy_calls) - assert expected_call in copy_calls + copy_certificate.assert_has_calls(expected_calls, any_order=True) -def _assert_restarted_daemons(daemons, superuser_run): +def _assert_restarted_daemons(daemons, try_restart): """Check that a call has restarted the daemons of a component.""" - run_calls = [ - mock_call for mock_call in superuser_run.mock_calls - if mock_call[1][0] == 'service' - ] - expected_calls = [ - call('service', ['try-restart', daemon]) for daemon in daemons - ] - assert len(expected_calls) == len(run_calls) - for expected_call in expected_calls: - assert expected_call in run_calls + expected_calls = [call(daemon) for daemon in daemons] + try_restart.assert_has_calls(expected_calls, any_order=True) -def test_setup_certificates(superuser_run, get_status, component): +def test_setup_certificates(copy_certificate, try_restart, get_status, + component): """Test that initial copying of certs for an app works.""" component.setup_certificates() - _assert_copy_certificate_called(component, superuser_run, { + _assert_copy_certificate_called(component, copy_certificate, { 'valid.example': 'valid', 'invalid.example': 'invalid' }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def test_setup_certificates_without_copy(superuser_run, get_status, component): +def test_setup_certificates_without_copy(copy_certificate, try_restart, + get_status, component): """Test that initial copying of certs for an app works.""" component.should_copy_certificates = False component.setup_certificates() - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons(component.daemons, try_restart) -def test_setup_certificates_with_app_domains(superuser_run, get_status, - component): +def test_setup_certificates_with_app_domains(copy_certificate, try_restart, + get_status, component): """Test that initial copying of certs for an app works.""" component._domains = ['irrelevant1.example', 'irrelevant2.example'] component.setup_certificates( app_domains=['valid.example', 'invalid.example']) - _assert_copy_certificate_called(component, superuser_run, { + _assert_copy_certificate_called(component, copy_certificate, { 'valid.example': 'valid', 'invalid.example': 'invalid' }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def test_setup_certificates_with_all_domains(domain_list, superuser_run, - get_status, component): +def test_setup_certificates_with_all_domains(domain_list, copy_certificate, + try_restart, get_status, + component): """Test that initial copying for certs works when app domains is '*'.""" component._domains = '*' component.setup_certificates() _assert_copy_certificate_called( - component, superuser_run, { + component, copy_certificate, { 'valid.example': 'valid', 'invalid1.example': 'invalid', 'invalid2.example': 'invalid' }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def _assert_compare_certificate_called(component, superuser_run, domains): +def _assert_compare_certificate_called(component, compare_certificate, + domains): """Check that compare certificate was called properly.""" expected_calls = [] for domain in domains: @@ -239,37 +238,34 @@ def _assert_compare_certificate_called(component, superuser_run, domains): '/etc/letsencrypt/live/{}/fullchain.pem'.format(domain) private_key_path = '/etc/test-app/{}/private.path'.format(domain) certificate_path = '/etc/test-app/{}/certificate.path'.format(domain) - expected_call = call('letsencrypt', [ - 'compare-certificate', '--managing-app', component.managing_app, - '--source-private-key-path', - str(source_private_key_path), '--source-certificate-path', - str(source_certificate_path), '--private-key-path', - private_key_path, '--certificate-path', certificate_path - ]) + expected_call = call(component.managing_app, + str(source_private_key_path), + str(source_certificate_path), private_key_path, + certificate_path) expected_calls.append(expected_call) - superuser_run.assert_has_calls(expected_calls) + compare_certificate.assert_has_calls(expected_calls, any_order=True) -def test_get_status(component, superuser_run, get_status): +def test_get_status(component, compare_certificate, get_status): """Test that getting domain status works.""" - superuser_run.return_value = json.dumps({'result': True}) + compare_certificate.return_value = True assert component.get_status() == { 'valid.example': 'valid', 'invalid.example': 'self-signed' } - _assert_compare_certificate_called(component, superuser_run, + _assert_compare_certificate_called(component, compare_certificate, ['valid.example']) -def test_get_status_outdate_copy(component, superuser_run, get_status): +def test_get_status_outdate_copy(component, compare_certificate, get_status): """Test that getting domain status works with outdated copy.""" - superuser_run.return_value = json.dumps({'result': False}) + compare_certificate.return_value = False assert component.get_status() == { 'valid.example': 'outdated-copy', 'invalid.example': 'self-signed' } - _assert_compare_certificate_called(component, superuser_run, + _assert_compare_certificate_called(component, compare_certificate, ['valid.example']) @@ -282,130 +278,139 @@ def test_get_status_without_copy(component, get_status): } -def test_on_certificate_obtained(superuser_run, component): +def test_on_certificate_obtained(copy_certificate, try_restart, component): """Test that certificate obtained event handler works.""" component.on_certificate_obtained(['valid.example', 'irrelevant.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, { + _assert_copy_certificate_called(component, copy_certificate, { 'valid.example': 'valid', }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_obtained_with_all_domains(superuser_run, component): +def test_on_certificate_obtained_with_all_domains(copy_certificate, + try_restart, component): """Test that certificate obtained event handler works for app with all domains. """ component._domains = '*' component.on_certificate_obtained(['valid.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, { + _assert_copy_certificate_called(component, copy_certificate, { 'valid.example': 'valid', }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_obtained_irrelevant(superuser_run, component): +def test_on_certificate_obtained_irrelevant(copy_certificate, try_restart, + component): """Test that certificate obtained event handler works with irrelevant domain. """ component.on_certificate_obtained( ['irrelevant.example'], '/etc/letsencrypt/live/irrelevant.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons([], superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons([], try_restart) -def test_on_certificate_obtained_without_copy(superuser_run, component): +def test_on_certificate_obtained_without_copy(copy_certificate, try_restart, + component): """Test that certificate obtained event handler works without copying.""" component.should_copy_certificates = False component.on_certificate_obtained(['valid.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_renewed(superuser_run, component): +def test_on_certificate_renewed(copy_certificate, try_restart, component): """Test that certificate renewed event handler works.""" component.on_certificate_renewed(['valid.example', 'irrelevant.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, { + _assert_copy_certificate_called(component, copy_certificate, { 'valid.example': 'valid', }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_renewed_irrelevant(superuser_run, component): +def test_on_certificate_renewed_irrelevant(copy_certificate, try_restart, + component): """Test that certificate renewed event handler works for irrelevant domains. """ component.on_certificate_renewed( ['irrelevant.example'], '/etc/letsencrypt/live/irrelevant.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons([], superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons([], try_restart) -def test_on_certificate_renewed_without_copy(superuser_run, component): +def test_on_certificate_renewed_without_copy(copy_certificate, try_restart, + component): """Test that certificate renewed event handler works without copying.""" component.should_copy_certificates = False component.on_certificate_renewed(['valid.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_revoked(superuser_run, component): +def test_on_certificate_revoked(copy_certificate, try_restart, component): """Test that certificate revoked event handler works.""" component.on_certificate_revoked(['valid.example', 'irrelevant.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, { + _assert_copy_certificate_called(component, copy_certificate, { 'valid.example': 'invalid', }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_revoked_irrelevant(superuser_run, component): +def test_on_certificate_revoked_irrelevant(copy_certificate, try_restart, + component): """Test that certificate revoked event handler works for irrelevant domains. """ component.on_certificate_revoked( ['irrelevant.example'], '/etc/letsencrypt/live/irrelevant.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons([], superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons([], try_restart) -def test_on_certificate_revoked_without_copy(superuser_run, component): +def test_on_certificate_revoked_without_copy(copy_certificate, try_restart, + component): """Test that certificate revoked event handler works without copying.""" component.should_copy_certificates = False component.on_certificate_revoked(['valid.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_deleted(superuser_run, component): +def test_on_certificate_deleted(copy_certificate, try_restart, component): """Test that certificate deleted event handler works.""" component.on_certificate_deleted(['valid.example', 'irrelevant.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, { + _assert_copy_certificate_called(component, copy_certificate, { 'valid.example': 'invalid', }) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_restarted_daemons(component.daemons, try_restart) -def test_on_certificate_deleted_irrelevant(superuser_run, component): +def test_on_certificate_deleted_irrelevant(copy_certificate, try_restart, + component): """Test that certificate deleted event handler works for irrelevant domains. """ component.on_certificate_deleted( ['irrelevant.example'], '/etc/letsencrypt/live/irrelevant.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons([], superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons([], try_restart) -def test_on_certificate_deleted_without_copy(superuser_run, component): +def test_on_certificate_deleted_without_copy(copy_certificate, try_restart, + component): """Test that certificate deleted event handler works without copying.""" component.should_copy_certificates = False component.on_certificate_deleted(['valid.example'], '/etc/letsencrypt/live/valid.example/') - _assert_copy_certificate_called(component, superuser_run, {}) - _assert_restarted_daemons(component.daemons, superuser_run) + _assert_copy_certificate_called(component, copy_certificate, {}) + _assert_restarted_daemons(component.daemons, try_restart) diff --git a/plinth/modules/letsencrypt/views.py b/plinth/modules/letsencrypt/views.py index f6b9906f1..5a946f680 100644 --- a/plinth/modules/letsencrypt/views.py +++ b/plinth/modules/letsencrypt/views.py @@ -11,7 +11,6 @@ from django.urls import reverse_lazy from django.utils.translation import gettext as _ from django.views.decorators.http import require_POST -from plinth.errors import ActionError from plinth.modules import letsencrypt from plinth.views import AppView @@ -41,11 +40,11 @@ def revoke(request, domain): _('Certificate successfully revoked for domain {domain}.' 'This may take a few moments to take effect.').format( domain=domain)) - except ActionError as exception: + except Exception as exception: messages.error( request, _('Failed to revoke certificate for domain {domain}: {error}'). - format(domain=domain, error=exception.args[2])) + format(domain=domain, error=exception.args)) return redirect(reverse_lazy('letsencrypt:index')) @@ -59,11 +58,11 @@ def obtain(request, domain): request, _('Certificate successfully obtained for domain {domain}').format( domain=domain)) - except ActionError as exception: + except Exception as exception: messages.error( request, _('Failed to obtain certificate for domain {domain}: {error}'). - format(domain=domain, error=exception.args[2])) + format(domain=domain, error=exception.args)) return redirect(reverse_lazy('letsencrypt:index')) @@ -76,11 +75,11 @@ def reobtain(request, domain): request, _('Certificate successfully obtained for domain {domain}').format( domain=domain)) - except ActionError as exception: + except Exception as exception: messages.error( request, _('Failed to obtain certificate for domain {domain}: {error}'). - format(domain=domain, error=exception.args[2])) + format(domain=domain, error=exception.args)) return redirect(reverse_lazy('letsencrypt:index')) @@ -93,10 +92,10 @@ def delete(request, domain): request, _('Certificate successfully deleted for domain {domain}').format( domain=domain)) - except ActionError as exception: + except Exception as exception: messages.error( request, _('Failed to delete certificate for domain {domain}: {error}'). - format(domain=domain, error=exception.args[2])) + format(domain=domain, error=exception.args)) return redirect(reverse_lazy('letsencrypt:index')) From bcdf374868851480605b73e91c4223b92a6477b0 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 08:14:26 -0700 Subject: [PATCH 36/90] matrixsynapse: Use privileged decorator for actions Tests: - Functional tests work - Initial setup works - Setup after install works - Domain is properly set - Configure domains is properly shown in the app page - Updating TURN configuration works - Configuration file is updated - Enabling/disabling public registration works - Configuration file is updated - App page show current status - FAIL: Daemon fails to start when public registration is enabled Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/matrixsynapse/__init__.py | 51 +++------ .../modules/matrixsynapse/privileged.py | 108 ++++++------------ .../matrixsynapse/tests/test_turn_config.py | 56 +++++---- plinth/modules/matrixsynapse/views.py | 28 ++--- 4 files changed, 90 insertions(+), 153 deletions(-) rename actions/matrixsynapse => plinth/modules/matrixsynapse/privileged.py (55%) mode change 100755 => 100644 diff --git a/plinth/modules/matrixsynapse/__init__.py b/plinth/modules/matrixsynapse/__init__.py index c007994df..d1043c19c 100644 --- a/plinth/modules/matrixsynapse/__init__.py +++ b/plinth/modules/matrixsynapse/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure matrix-synapse server. -""" +"""FreedomBox app to configure matrix-synapse server.""" import logging import os @@ -11,7 +9,6 @@ from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from ruamel.yaml.util import load_yaml_guess_indent -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.daemon import Daemon @@ -23,7 +20,7 @@ from plinth.modules.letsencrypt.components import LetsEncrypt from plinth.package import Packages, install from plinth.utils import format_lazy, is_non_empty_file -from . import manifest +from . import manifest, privileged _description = [ _('Matrix is an new ' @@ -41,16 +38,6 @@ _description = [ logger = logging.getLogger(__name__) -CONF_DIR = "/etc/matrix-synapse/conf.d/" - -ORIG_CONF_PATH = '/etc/matrix-synapse/homeserver.yaml' -SERVER_NAME_PATH = CONF_DIR + 'server_name.yaml' -STATIC_CONF_PATH = CONF_DIR + 'freedombox-static.yaml' -LISTENERS_CONF_PATH = CONF_DIR + 'freedombox-listeners.yaml' -REGISTRATION_CONF_PATH = CONF_DIR + 'freedombox-registration.yaml' -TURN_CONF_PATH = CONF_DIR + 'freedombox-turn.yaml' -OVERRIDDEN_TURN_CONF_PATH = CONF_DIR + 'turn.yaml' - class MatrixSynapseApp(app_module.App): """FreedomBox app for Matrix Synapse.""" @@ -122,7 +109,7 @@ class MatrixSynapseApp(app_module.App): if old_version and old_version < 6: upgrade() else: - actions.superuser_run('matrixsynapse', ['post-install']) + privileged.post_install() if not old_version: self.enable() @@ -144,14 +131,13 @@ class MatrixSynapseTurnConsumer(TurnConsumer): def upgrade(): """Upgrade matrix-synapse configuration to avoid conffile prompt.""" - public_registration_status = get_public_registration_status() - actions.superuser_run('matrixsynapse', ['move-old-conf']) + public_registration_status = privileged.public_registration('status') + privileged.move_old_conf() install(['matrix-synapse'], force_configuration='new', reinstall=True, force_missing_configuration=True) - actions.superuser_run('matrixsynapse', ['post-install']) + privileged.post_install() if public_registration_status: - actions.superuser_run('matrixsynapse', - ['public-registration', 'enable']) + privileged.public_registration('enable') def setup_domain(domain_name): @@ -159,13 +145,12 @@ def setup_domain(domain_name): app = app_module.App.get('matrixsynapse') app.get_component('letsencrypt-matrixsynapse').setup_certificates( [domain_name]) - actions.superuser_run('matrixsynapse', - ['setup', '--domain-name', domain_name]) + privileged.setup(domain_name) def is_setup(): """Return whether the Matrix Synapse server is setup.""" - return os.path.exists(SERVER_NAME_PATH) + return os.path.exists(privileged.SERVER_NAME_PATH) def get_domains(): @@ -182,7 +167,7 @@ def get_configured_domain_name(): if not is_setup(): return None - with open(SERVER_NAME_PATH, encoding='utf-8') as config_file: + with open(privileged.SERVER_NAME_PATH, encoding='utf-8') as config_file: config, _, _ = load_yaml_guess_indent(config_file) return config['server_name'] @@ -190,8 +175,8 @@ def get_configured_domain_name(): def get_turn_configuration() -> (List[str], str, bool): """Return TurnConfiguration if setup else empty.""" - for file_path, managed in ((OVERRIDDEN_TURN_CONF_PATH, False), - (TURN_CONF_PATH, True)): + for file_path, managed in ((privileged.OVERRIDDEN_TURN_CONF_PATH, False), + (privileged.TURN_CONF_PATH, True)): if is_non_empty_file(file_path): with open(file_path, encoding='utf-8') as config_file: config, _, _ = load_yaml_guess_indent(config_file) @@ -202,13 +187,6 @@ def get_turn_configuration() -> (List[str], str, bool): return (TurnConfiguration(), True) -def get_public_registration_status() -> bool: - """Return whether public registration is enabled.""" - output = actions.superuser_run('matrixsynapse', - ['public-registration', 'status']) - return output.strip() == 'enabled' - - def get_certificate_status(): """Return the status of certificate for the configured domain.""" app = app_module.App.get('matrixsynapse') @@ -226,7 +204,4 @@ def update_turn_configuration(config: TurnConfiguration, managed=True, if not force and app.needs_setup(): return - params = ['configure-turn'] - params += ['--managed'] if managed else [] - actions.superuser_run('matrixsynapse', params, - input=config.to_json().encode()) + privileged.configure_turn(managed, config.to_json()) diff --git a/actions/matrixsynapse b/plinth/modules/matrixsynapse/privileged.py old mode 100755 new mode 100644 similarity index 55% rename from actions/matrixsynapse rename to plinth/modules/matrixsynapse/privileged.py index 75e22368f..d8b98111e --- a/actions/matrixsynapse +++ b/plinth/modules/matrixsynapse/privileged.py @@ -1,24 +1,25 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Matrix-Synapse server. -""" +"""Configure Matrix-Synapse server.""" -import argparse import json import os import pathlib -import sys +from typing import Optional import yaml from plinth import action_utils -from plinth.modules.matrixsynapse import (LISTENERS_CONF_PATH, ORIG_CONF_PATH, - REGISTRATION_CONF_PATH, - STATIC_CONF_PATH) +from plinth.actions import privileged -TURN_CONF_PATH = '/etc/matrix-synapse/conf.d/freedombox-turn.yaml' -OVERRIDDEN_TURN_CONF_PATH = '/etc/matrix-synapse/conf.d/turn.yaml' +CONF_DIR = "/etc/matrix-synapse/conf.d/" + +ORIG_CONF_PATH = '/etc/matrix-synapse/homeserver.yaml' +SERVER_NAME_PATH = CONF_DIR + 'server_name.yaml' +STATIC_CONF_PATH = CONF_DIR + 'freedombox-static.yaml' +LISTENERS_CONF_PATH = CONF_DIR + 'freedombox-listeners.yaml' +REGISTRATION_CONF_PATH = CONF_DIR + 'freedombox-registration.yaml' +TURN_CONF_PATH = CONF_DIR + 'freedombox-turn.yaml' +OVERRIDDEN_TURN_CONF_PATH = CONF_DIR + 'turn.yaml' STATIC_CONFIG = { 'max_upload_size': @@ -40,38 +41,8 @@ STATIC_CONFIG = { } -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('post-install', help='Perform post install steps') - help_pubreg = 'Enable/Disable/Status public user registration.' - pubreg = subparsers.add_parser('public-registration', help=help_pubreg) - pubreg.add_argument('command', choices=('enable', 'disable', 'status'), - help=help_pubreg) - setup = subparsers.add_parser('setup', help='Set domain name for Matrix') - setup.add_argument( - '--domain-name', - help='The domain name that will be used by Matrix Synapse') - - subparsers.add_parser( - 'move-old-conf', - help='Move old configuration file to backup before reinstall') - - turn = subparsers.add_parser( - 'configure-turn', - help='Configure a TURN server for use with Matrix Synapse') - turn.add_argument( - '--managed', required=False, default=False, action='store_true', - help='Whether configuration is provided by user or auto-managed by ' - 'FreedomBox') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_post_install(_): +@privileged +def post_install(): """Perform post installation configuration.""" with open(STATIC_CONF_PATH, 'w', encoding='utf-8') as static_conf_file: yaml.dump(STATIC_CONFIG, static_conf_file) @@ -91,15 +62,19 @@ def subcommand_post_install(_): yaml.dump({'listeners': listeners}, listeners_conf_file) -def subcommand_setup(arguments): +@privileged +def setup(domain_name: str): """Configure the domain name for matrix-synapse package.""" - domain_name = arguments.domain_name action_utils.dpkg_reconfigure('matrix-synapse', {'server-name': domain_name}) -def subcommand_public_registration(argument): +@privileged +def public_registration(command: str) -> Optional[bool]: """Enable/Disable/Status public user registration.""" + if command not in ('enable', 'disable', 'status'): + raise ValueError('Invalid command') + try: with open(REGISTRATION_CONF_PATH, encoding='utf-8') as reg_conf_file: config = yaml.load(reg_conf_file) @@ -112,25 +87,22 @@ def subcommand_public_registration(argument): orig_config.get('enable_registration', False) } - if argument.command == 'status': - if config['enable_registration']: - print('enabled') - return - else: - print('disabled') - return - elif argument.command == 'enable': + if command == 'status': + return bool(config['enable_registration']) + elif command == 'enable': config['enable_registration'] = True - elif argument.command == 'disable': + elif command == 'disable': config['enable_registration'] = False with open(REGISTRATION_CONF_PATH, 'w', encoding='utf-8') as reg_conf_file: yaml.dump(config, reg_conf_file) action_utils.service_try_restart('matrix-synapse') + return None -def subcommand_move_old_conf(_arguments): +@privileged +def move_old_conf(): """Move old configuration to backup so it can be restored by reinstall.""" conf_file = pathlib.Path(ORIG_CONF_PATH) if conf_file.exists(): @@ -138,8 +110,8 @@ def subcommand_move_old_conf(_arguments): conf_file.replace(backup_file) -def _set_turn_config(conf_file): - turn_server_config = json.loads(''.join(sys.stdin)) +def _set_turn_config(conf_file, conf): + turn_server_config = json.loads(conf) if not turn_server_config['uris']: # No valid configuration, remove the configuration file @@ -161,22 +133,12 @@ def _set_turn_config(conf_file): yaml.dump(config, turn_config) -def subcommand_configure_turn(arguments): +@privileged +def configure_turn(managed: bool, conf: str): """Set parameters for the STUN/TURN server to use with Matrix Synapse.""" - if arguments.managed: - _set_turn_config(TURN_CONF_PATH) + if managed: + _set_turn_config(TURN_CONF_PATH, conf) else: - _set_turn_config(OVERRIDDEN_TURN_CONF_PATH) + _set_turn_config(OVERRIDDEN_TURN_CONF_PATH, conf) action_utils.service_try_restart('matrix-synapse') - - -def main(): - arguments = parse_arguments() - sub_command = arguments.subcommand.replace('-', '_') - sub_command_method = globals()['subcommand_' + sub_command] - sub_command_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/matrixsynapse/tests/test_turn_config.py b/plinth/modules/matrixsynapse/tests/test_turn_config.py index 2f48705f0..9a5f7b961 100644 --- a/plinth/modules/matrixsynapse/tests/test_turn_config.py +++ b/plinth/modules/matrixsynapse/tests/test_turn_config.py @@ -9,8 +9,10 @@ import pytest from plinth.modules import matrixsynapse from plinth.modules.coturn.components import TurnConfiguration +from plinth.modules.matrixsynapse import privileged -actions_name = 'matrixsynapse' +pytestmark = pytest.mark.usefixtures('mock_privileged') +privileged_modules_to_mock = ['plinth.modules.matrixsynapse.privileged'] @pytest.fixture(name='managed_turn_conf_file') @@ -28,29 +30,27 @@ def fixture_overridden_turn_conf_file(tmp_path): @pytest.fixture(autouse=True) -def fixture_set_paths(actions_module, capsys, managed_turn_conf_file, - overridden_turn_conf_file): +def fixture_set_paths(managed_turn_conf_file, overridden_turn_conf_file): """Run actions with custom root path.""" - actions_module.TURN_CONF_PATH = managed_turn_conf_file - actions_module.OVERRIDDEN_TURN_CONF_PATH = overridden_turn_conf_file - with patch('plinth.action_utils.service_try_restart'): + privileged.TURN_CONF_PATH = managed_turn_conf_file + privileged.OVERRIDDEN_TURN_CONF_PATH = overridden_turn_conf_file + with patch('plinth.privileged.service.try_restart'): yield @pytest.fixture(name='test_configuration', autouse=True) -def fixture_test_configuration(call_action, managed_turn_conf_file, +def fixture_test_configuration(managed_turn_conf_file, overridden_turn_conf_file): """Use a separate Matrix Synapse configuration for tests. - Overrides TURN configuration files and patches actions.superuser_run - with the fixture call_action + Overrides TURN configuration files. """ - with (patch('plinth.modules.matrixsynapse.TURN_CONF_PATH', + matrixsynapse = 'plinth.modules.matrixsynapse' + with (patch(f'{matrixsynapse}.privileged.TURN_CONF_PATH', managed_turn_conf_file), - patch('plinth.modules.matrixsynapse.OVERRIDDEN_TURN_CONF_PATH', + patch(f'{matrixsynapse}.privileged.OVERRIDDEN_TURN_CONF_PATH', overridden_turn_conf_file), - patch('plinth.modules.matrixsynapse.is_setup', return_value=True), - patch('plinth.actions.superuser_run', call_action), + patch(f'{matrixsynapse}.is_setup', return_value=True), patch('plinth.app.App.get') as app_get): app = Mock() app_get.return_value = app @@ -71,14 +71,12 @@ updated_coturn_configuration = TurnConfiguration( 'aiP02OsbkC7BUeKvKzhAsTZ8MEwMd3yTwpr2uvbOxgWe51AGyOlj6WGuCyqj7iaO') -def _set_managed_configuration(monkeypatch, config=coturn_configuration): - monkeypatch.setattr('sys.stdin', config.to_json()) +def _set_managed_configuration(config=coturn_configuration): matrixsynapse.update_turn_configuration(config) -def _set_overridden_configuration(monkeypatch, +def _set_overridden_configuration( config=overridden_configuration): - monkeypatch.setattr('sys.stdin', config.to_json()) matrixsynapse.update_turn_configuration(config, managed=False) @@ -90,30 +88,30 @@ def _assert_conf(expected_configuration, expected_managed): assert managed == expected_managed -def test_managed_turn_server_configuration(monkeypatch): +def test_managed_turn_server_configuration(): """Test setting and getting managed TURN server configuration.""" - _set_managed_configuration(monkeypatch) + _set_managed_configuration() _assert_conf(coturn_configuration, True) -def test_overridden_turn_server_configuration(monkeypatch): +def test_overridden_turn_server_configuration(): """Test setting and getting overridden TURN sever configuration.""" - _set_overridden_configuration(monkeypatch) + _set_overridden_configuration() _assert_conf(overridden_configuration, False) -def test_revert_to_managed_turn_server_configuration(monkeypatch): +def test_revert_to_managed_turn_server_configuration(): """Test setting and getting overridden TURN sever configuration.""" # Had to do all 3 operations because all fixtures were function-scoped - _set_managed_configuration(monkeypatch) - _set_overridden_configuration(monkeypatch) - _set_overridden_configuration(monkeypatch, TurnConfiguration()) + _set_managed_configuration() + _set_overridden_configuration() + _set_overridden_configuration(TurnConfiguration()) _assert_conf(coturn_configuration, True) -def test_coturn_configuration_update_after_admin_override(monkeypatch): +def test_coturn_configuration_update_after_admin_override(): """Test that overridden conf prevails even if managed conf is updated.""" - _set_managed_configuration(monkeypatch) - _set_overridden_configuration(monkeypatch) - _set_managed_configuration(monkeypatch, updated_coturn_configuration) + _set_managed_configuration() + _set_overridden_configuration() + _set_managed_configuration(updated_coturn_configuration) _assert_conf(overridden_configuration, False) diff --git a/plinth/modules/matrixsynapse/views.py b/plinth/modules/matrixsynapse/views.py index 3d8ba9a30..ad47b6de7 100644 --- a/plinth/modules/matrixsynapse/views.py +++ b/plinth/modules/matrixsynapse/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the Matrix Synapse module. -""" +"""Views for the Matrix Synapse module.""" from django.contrib import messages from django.shortcuts import redirect @@ -9,19 +7,19 @@ from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views.generic import FormView -from plinth import actions from plinth import app as app_module from plinth.forms import DomainSelectionForm from plinth.modules import matrixsynapse, names from plinth.modules.coturn.components import TurnConfiguration from plinth.views import AppView -from . import get_public_registration_status, get_turn_configuration +from . import get_turn_configuration, privileged from .forms import MatrixSynapseForm class SetupView(FormView): """Show matrix-synapse setup page.""" + template_name = 'matrix-synapse-pre-setup.html' form_class = DomainSelectionForm success_url = reverse_lazy('matrixsynapse:index') @@ -46,6 +44,7 @@ class SetupView(FormView): class MatrixSynapseAppView(AppView): """Show matrix-synapse service page.""" + app_id = 'matrixsynapse' template_name = 'matrix-synapse.html' form_class = MatrixSynapseForm @@ -69,21 +68,24 @@ class MatrixSynapseAppView(AppView): initial = super().get_initial() config, managed = get_turn_configuration() initial.update({ - 'enable_public_registration': get_public_registration_status(), - 'enable_managed_turn': managed, - 'turn_uris': '\n'.join(config.uris), - 'shared_secret': config.shared_secret + 'enable_public_registration': + privileged.public_registration('status'), + 'enable_managed_turn': + managed, + 'turn_uris': + '\n'.join(config.uris), + 'shared_secret': + config.shared_secret }) return initial @staticmethod def _handle_public_registrations(new_config): + if new_config['enable_public_registration']: - actions.superuser_run('matrixsynapse', - ['public-registration', 'enable']) + privileged.public_registration('enable') else: - actions.superuser_run('matrixsynapse', - ['public-registration', 'disable']) + privileged.public_registration('disable') @staticmethod def _handle_turn_configuration(old_config, new_config): From f5bfd7a9db7314892ce32dc1e7d644d75f512436 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 29 Aug 2022 11:11:40 -0700 Subject: [PATCH 37/90] mediawiki: Use privileged decorator for actions Tests: - Functional tests works (when libpam-tmpdir is removed) - Initial setup works - Website is accessible - sqlite file is created - Database update is triggered - Changing skin/admin password/public registrations/private mode/site name works - Configuration file is updated - App page shows the current value - Website is reflects the correct value - When private mode is enabled, public registrations are automatically disabled Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/mediawiki/__init__.py | 39 +--- .../modules/mediawiki/privileged.py | 176 ++++++------------ .../mediawiki/tests/test_functional.py | 45 +++-- .../modules/mediawiki/tests/test_settings.py | 20 +- plinth/modules/mediawiki/views.py | 47 +++-- 5 files changed, 129 insertions(+), 198 deletions(-) rename actions/mediawiki => plinth/modules/mediawiki/privileged.py (51%) mode change 100755 => 100644 diff --git a/plinth/modules/mediawiki/__init__.py b/plinth/modules/mediawiki/__init__.py index b2575cb4a..0a9537f8e 100644 --- a/plinth/modules/mediawiki/__init__.py +++ b/plinth/modules/mediawiki/__init__.py @@ -1,14 +1,11 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure MediaWiki. -""" +"""FreedomBox app to configure MediaWiki.""" import re from urllib.parse import urlparse from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.daemon import Daemon @@ -17,7 +14,7 @@ from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.package import Packages -from . import manifest +from . import manifest, privileged _description = [ _('MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia ' @@ -96,8 +93,8 @@ class MediaWikiApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('mediawiki', ['setup']) - actions.superuser_run('mediawiki', ['update']) + privileged.setup() + privileged.update() self.enable() @@ -107,20 +104,7 @@ class Shortcut(frontpage.Shortcut): def enable(self): """When enabled, check if MediaWiki is in private mode.""" super().enable() - self.login_required = is_private_mode_enabled() - - -def is_public_registration_enabled(): - """Return whether public registration is enabled.""" - output = actions.superuser_run('mediawiki', - ['public-registrations', 'status']) - return output.strip() == 'enabled' - - -def is_private_mode_enabled(): - """Return whether private mode is enabled or disabled.""" - output = actions.superuser_run('mediawiki', ['private-mode', 'status']) - return output.strip() == 'enabled' + self.login_required = privileged.private_mode('status') def _get_config_value_in_file(setting_name, config_file): @@ -144,11 +128,6 @@ def get_default_skin(): return _get_config_value('$wgDefaultSkin') -def set_default_skin(skin): - """Set the value of the default skin.""" - actions.superuser_run('mediawiki', ['set-default-skin', skin]) - - def get_server_url(): """Return the value of the server URL.""" server_url = _get_config_value('$wgServer') @@ -161,15 +140,9 @@ def set_server_url(domain): if domain.endswith('.onion'): protocol = 'http' - actions.superuser_run('mediawiki', - ['set-server-url', f'{protocol}://{domain}']) + privileged.set_server_url(f'{protocol}://{domain}') def get_site_name(): """Return the value of MediaWiki's site name.""" return _get_config_value('$wgSitename') or 'Wiki' - - -def set_site_name(site_name): - """Set the value of $wgSitename.""" - actions.superuser_run('mediawiki', ['set-site-name', site_name]) diff --git a/actions/mediawiki b/plinth/modules/mediawiki/privileged.py old mode 100755 new mode 100644 similarity index 51% rename from actions/mediawiki rename to plinth/modules/mediawiki/privileged.py index bf3fcd9a3..d011f37e0 --- a/actions/mediawiki +++ b/plinth/modules/mediawiki/privileged.py @@ -1,15 +1,12 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for MediaWiki. -""" +"""Configure MediaWiki.""" -import argparse import os import subprocess -import sys import tempfile +from typing import Optional +from plinth.actions import privileged from plinth.utils import generate_password MAINTENANCE_SCRIPTS_DIR = "/usr/share/mediawiki/maintenance" @@ -17,49 +14,6 @@ CONF_FILE = '/etc/mediawiki/FreedomBoxSettings.php' LOCAL_SETTINGS_CONF = '/etc/mediawiki/LocalSettings.php' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Setup MediaWiki') - subparsers.add_parser('update', help='Run MediaWiki update script') - - help_pub_reg = 'Enable/Disable/Status public user registration.' - pub_reg = subparsers.add_parser('public-registrations', help=help_pub_reg) - pub_reg.add_argument('command', choices=('enable', 'disable', 'status'), - help=help_pub_reg) - - help_private_mode = 'Enable/Disable/Status private mode.' - private_mode = subparsers.add_parser('private-mode', - help=help_private_mode) - private_mode.add_argument('command', - choices=('enable', 'disable', 'status'), - help=help_private_mode) - - change_password = subparsers.add_parser('change-password', - help='Change user password') - change_password.add_argument('--username', default='admin', - help='name of the MediaWiki user') - change_password.add_argument('--password', - help='new password for the MediaWiki user') - - default_skin = subparsers.add_parser('set-default-skin', - help='Set the default skin') - default_skin.add_argument('skin', help='name of the skin') - - server_url = subparsers.add_parser( - 'set-server-url', help='Set the value of $wgServer for this server') - server_url.add_argument('server_url', help='value of $wgServer') - - site_name = subparsers.add_parser( - 'set-site-name', help='Set the value of $wgSitename for this Wiki') - site_name.add_argument('site_name', help='value of $wgSitename') - - subparsers.required = True - return parser.parse_args() - - def _get_php_command(): """Return the PHP command that should be used on CLI. @@ -82,7 +36,8 @@ def _get_php_command(): return f'php{version}' -def subcommand_setup(_): +@privileged +def setup(): """Run the installer script to create database and configuration file.""" data_dir = '/var/lib/mediawiki-db/' if not os.path.exists(data_dir): @@ -103,10 +58,10 @@ def subcommand_setup(_): ]) subprocess.run(['chmod', '-R', 'o-rwx', data_dir], check=True) subprocess.run(['chown', '-R', 'www-data:www-data', data_dir], check=True) - include_custom_config() + _include_custom_config() -def include_custom_config(): +def _include_custom_config(): """Include FreedomBox specific configuration in LocalSettings.php.""" with open(LOCAL_SETTINGS_CONF, 'r', encoding='utf-8') as conf_file: lines = conf_file.readlines() @@ -133,26 +88,30 @@ def include_custom_config(): conf_file.writelines(lines) -def subcommand_change_password(arguments): - """Change the password for a given user""" - new_password = ''.join(sys.stdin) +@privileged +def change_password(username: str, password: str): + """Change the password for a given user.""" change_password_script = os.path.join(MAINTENANCE_SCRIPTS_DIR, 'changePassword.php') subprocess.check_call([ - _get_php_command(), change_password_script, '--user', - arguments.username, '--password', new_password + _get_php_command(), change_password_script, '--user', username, + '--password', password ]) -def subcommand_update(_): +@privileged +def update(): """Run update.php maintenance script when version upgrades happen.""" update_script = os.path.join(MAINTENANCE_SCRIPTS_DIR, 'update.php') subprocess.check_call([_get_php_command(), update_script, '--quick']) -def subcommand_public_registrations(arguments): +@privileged +def public_registrations(command: str) -> Optional[bool]: """Enable or Disable public registrations for MediaWiki.""" + if command not in ('enable', 'disable', 'status'): + raise ValueError('Invalid command') with open(CONF_FILE, 'r', encoding='utf-8') as conf_file: lines = conf_file.readlines() @@ -160,28 +119,31 @@ def subcommand_public_registrations(arguments): def is_pub_reg_line(line): return line.startswith("$wgGroupPermissions['*']['createaccount']") - if arguments.command == 'status': + if command == 'status': conf_lines = list(filter(is_pub_reg_line, lines)) - if conf_lines: - print('enabled' if 'true' in conf_lines[0] else 'disabled') - else: - print('disabled') - else: - with open(CONF_FILE, 'w', encoding='utf-8') as conf_file: - for line in lines: - if is_pub_reg_line(line): - words = line.split() - if arguments.command == 'enable': - words[-1] = 'true;' - else: - words[-1] = 'false;' - conf_file.write(" ".join(words) + '\n') + return bool(conf_lines and 'true' in conf_lines[0]) + + with open(CONF_FILE, 'w', encoding='utf-8') as conf_file: + for line in lines: + if is_pub_reg_line(line): + words = line.split() + if command == 'enable': + words[-1] = 'true;' else: - conf_file.write(line) + words[-1] = 'false;' + conf_file.write(" ".join(words) + '\n') + else: + conf_file.write(line) + + return None -def subcommand_private_mode(arguments): - """Enable or Disable Private mode for wiki""" +@privileged +def private_mode(command: str): + """Enable or Disable Private mode for wiki.""" + if command not in ('enable', 'disable', 'status'): + raise ValueError('Invalid command') + with open(CONF_FILE, 'r', encoding='utf-8') as conf_file: lines = conf_file.readlines() @@ -189,25 +151,22 @@ def subcommand_private_mode(arguments): return line.startswith("$wgGroupPermissions['*']['read']") read_conf_lines = list(filter(is_read_line, lines)) - if arguments.command == 'status': - if read_conf_lines and 'false' in read_conf_lines[0]: - print('enabled') - else: - print('disabled') - else: - with open(CONF_FILE, 'w', encoding='utf-8') as conf_file: - conf_value = 'false;' if arguments.command == 'enable' else 'true;' - for line in lines: - if is_read_line(line): - words = line.split() - words[-1] = conf_value - conf_file.write(" ".join(words) + '\n') - else: - conf_file.write(line) + if command == 'status': + return (read_conf_lines and 'false' in read_conf_lines[0]) - if not read_conf_lines: - conf_file.write("$wgGroupPermissions['*']['read'] = " + - conf_value + '\n') + with open(CONF_FILE, 'w', encoding='utf-8') as conf_file: + conf_value = 'false;' if command == 'enable' else 'true;' + for line in lines: + if is_read_line(line): + words = line.split() + words[-1] = conf_value + conf_file.write(" ".join(words) + '\n') + else: + conf_file.write(line) + + if not read_conf_lines: + conf_file.write("$wgGroupPermissions['*']['read'] = " + + conf_value + '\n') def _update_setting(setting_name, setting_line): @@ -229,31 +188,20 @@ def _update_setting(setting_name, setting_line): conf_file.writelines(lines) -def subcommand_set_default_skin(arguments): +@privileged +def set_default_skin(skin: str): """Set a default skin.""" - skin = arguments.skin _update_setting('$wgDefaultSkin ', f'$wgDefaultSkin = "{skin}";\n') -def subcommand_set_server_url(arguments): +@privileged +def set_server_url(server_url: str): """Set the value of $wgServer for this MediaWiki server.""" # This is a required setting from MediaWiki 1.34 - _update_setting('$wgServer', f'$wgServer = "{arguments.server_url}";\n') + _update_setting('$wgServer', f'$wgServer = "{server_url}";\n') -def subcommand_set_site_name(arguments): +@privileged +def set_site_name(site_name: str): """Set the value of $wgSitename for this MediaWiki server.""" - _update_setting('$wgSitename', f'$wgSitename = "{arguments.site_name}";\n') - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() + _update_setting('$wgSitename', f'$wgSitename = "{site_name}";\n') diff --git a/plinth/modules/mediawiki/tests/test_functional.py b/plinth/modules/mediawiki/tests/test_functional.py index 768521950..19a6a5523 100644 --- a/plinth/modules/mediawiki/tests/test_functional.py +++ b/plinth/modules/mediawiki/tests/test_functional.py @@ -25,9 +25,21 @@ class TestMediawikiApp(functional.BaseAppTests): """Setup the app.""" functional.login(session_browser) functional.install(session_browser, 'mediawiki') + functional.app_enable(session_browser, 'mediawiki') _set_domain(session_browser) + _set_admin_password(session_browser, 'whatever123') - def test_public_registrations(self, session_browser): + @pytest.fixture(name='no_login') + def fixture_no_login(self, session_browser): + """Ensure logout from MediaWiki.""" + _logout(session_browser) + + @pytest.fixture(name='login') + def fixture_login(self, session_browser): + """Ensure login to MediaWiki.""" + _login_with_credentials(session_browser, 'admin', 'whatever123') + + def test_public_registrations(self, session_browser, no_login): """Test enabling public registrations.""" _enable_public_registrations(session_browser) _verify_create_account_link(session_browser) @@ -35,7 +47,7 @@ class TestMediawikiApp(functional.BaseAppTests): _disable_public_registrations(session_browser) _verify_no_create_account_link(session_browser) - def test_private_mode(self, session_browser): + def test_private_mode(self, session_browser, no_login): """Test enabling private mode.""" _enable_private_mode(session_browser) _verify_no_create_account_link(session_browser) @@ -44,7 +56,8 @@ class TestMediawikiApp(functional.BaseAppTests): _disable_private_mode(session_browser) _verify_anonymous_reads_edits_link(session_browser) - def test_private_mode_public_registrations(self, session_browser): + def test_private_mode_public_registrations(self, session_browser, + no_login): """Test interactive between private mode and public registrations. Requires JS.""" @@ -58,25 +71,18 @@ class TestMediawikiApp(functional.BaseAppTests): _enable_public_registrations(session_browser) _verify_create_account_link(session_browser) - def test_upload_files(self, session_browser): - """Test that logged in user can see upload files option. - - Requires JS.""" - _set_admin_password(session_browser, 'whatever123') - _login_with_credentials(session_browser, 'admin', 'whatever123') - - def test_upload_images(self, session_browser): + def test_upload_images(self, session_browser, login): """Test uploading an image.""" _upload_image(session_browser, 'admin', 'whatever123', 'noise.png') assert _image_exists(session_browser, 'Noise.png') - def test_upload_svg_image(self, session_browser): + def test_upload_svg_image(self, session_browser, login): """Test uploading an SVG image.""" _upload_image(session_browser, 'admin', 'whatever123', 'apps-background.svg') assert _image_exists(session_browser, 'Apps-background.svg') - def test_backup_restore(self, session_browser): + def test_backup_restore(self, session_browser, login): """Test backup and restore of pages and images.""" if not _image_exists(session_browser, 'Noise.png'): _upload_image(session_browser, 'admin', 'whatever123', 'Noise.png') @@ -147,19 +153,19 @@ def _verify_no_create_account_link(browser): lambda: not _is_create_account_available(browser)) -def _is_anonymouse_read_allowed(browser): +def _is_anonymous_read_allowed(browser): """Load the main page and check if anonymous reading is allowed.""" functional.visit(browser, '/mediawiki') return browser.is_element_present_by_id('ca-nstab-main') def _verify_anonymous_reads_edits_link(browser): - assert functional.eventually(_is_anonymouse_read_allowed, args=[browser]) + assert functional.eventually(_is_anonymous_read_allowed, args=[browser]) def _verify_no_anonymous_reads_edits_link(browser): assert functional.eventually( - lambda: not _is_anonymouse_read_allowed(browser)) + lambda: not _is_anonymous_read_allowed(browser)) assert browser.is_element_present_by_id('ca-nstab-special') @@ -179,6 +185,13 @@ def _login_with_credentials(browser, username, password): args=['t-upload']) +def _logout(browser): + """Logout from MediaWiki.""" + functional.visit(browser, '/mediawiki/Special:UserLogout') + if browser.find_by_css('#bodyContent form'): + functional.submit(browser, form_class='oo-ui-formLayout') + + def _upload_image(browser, username, password, image, ignore_warnings=True): """Upload an image to MediaWiki. Idempotent.""" functional.visit(browser, '/mediawiki') diff --git a/plinth/modules/mediawiki/tests/test_settings.py b/plinth/modules/mediawiki/tests/test_settings.py index 2bd9b0644..20d0c9e4a 100644 --- a/plinth/modules/mediawiki/tests/test_settings.py +++ b/plinth/modules/mediawiki/tests/test_settings.py @@ -10,15 +10,17 @@ from unittest.mock import patch import pytest from plinth.modules import mediawiki +from plinth.modules.mediawiki import privileged -actions_name = 'mediawiki' +pytestmark = pytest.mark.usefixtures('mock_privileged') current_directory = pathlib.Path(__file__).parent +privileged_modules_to_mock = ['plinth.modules.mediawiki.privileged'] @pytest.fixture(autouse=True) -def fixture_setup_configuration(actions_module, conf_file): +def fixture_setup_configuration(conf_file): """Set configuration file path in actions module.""" - actions_module.CONF_FILE = conf_file + privileged.CONF_FILE = conf_file @pytest.fixture(name='conf_file') @@ -34,12 +36,11 @@ def fixture_conf_file(tmp_path): @pytest.fixture(name='test_configuration', autouse=True) -def fixture_test_configuration(call_action, conf_file): +def fixture_test_configuration(conf_file): """Use a separate MediaWiki configuration for tests. Uses local FreedomBoxStaticSettings.php, a temp version of - FreedomBoxSettings.php and patches actions.superuser_run with the fixture - call_action + FreedomBoxSettings.php """ data_directory = pathlib.Path(__file__).parent.parent / 'data' @@ -47,8 +48,7 @@ def fixture_test_configuration(call_action, conf_file): mediawiki.STATIC_CONFIG_FILE.split('/')[-1]) with patch('plinth.modules.mediawiki.STATIC_CONFIG_FILE', static_config_file), \ - patch('plinth.modules.mediawiki.USER_CONFIG_FILE', conf_file), \ - patch('plinth.actions.superuser_run', call_action): + patch('plinth.modules.mediawiki.USER_CONFIG_FILE', conf_file): yield @@ -56,7 +56,7 @@ def test_default_skin(): """Test getting and setting the default skin.""" assert mediawiki.get_default_skin() == 'timeless' new_skin = 'vector' - mediawiki.set_default_skin(new_skin) + privileged.set_default_skin(new_skin) assert mediawiki.get_default_skin() == new_skin @@ -72,5 +72,5 @@ def test_site_name(): """Test getting and setting $wgSitename.""" assert mediawiki.get_site_name() == 'Wiki' new_site_name = 'My MediaWiki' - mediawiki.set_site_name(new_site_name) + privileged.set_site_name(new_site_name) assert mediawiki.get_site_name() == new_site_name diff --git a/plinth/modules/mediawiki/views.py b/plinth/modules/mediawiki/views.py index 15e3e7b06..f08b5e789 100644 --- a/plinth/modules/mediawiki/views.py +++ b/plinth/modules/mediawiki/views.py @@ -1,21 +1,16 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring MediaWiki. -""" +"""FreedomBox app for configuring MediaWiki.""" import logging from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import actions from plinth import app as app_module from plinth import views -from plinth.errors import ActionError from plinth.modules import mediawiki -from . import (get_default_skin, get_server_url, get_site_name, - is_private_mode_enabled, is_public_registration_enabled) +from . import get_default_skin, get_server_url, get_site_name, privileged from .forms import MediaWikiForm logger = logging.getLogger(__name__) @@ -23,6 +18,7 @@ logger = logging.getLogger(__name__) class MediaWikiAppView(views.AppView): """App configuration page.""" + app_id = 'mediawiki' form_class = MediaWikiForm template_name = 'mediawiki.html' @@ -31,11 +27,16 @@ class MediaWikiAppView(views.AppView): """Return the values to fill in the form.""" initial = super().get_initial() initial.update({ - 'enable_public_registrations': is_public_registration_enabled(), - 'enable_private_mode': is_private_mode_enabled(), - 'default_skin': get_default_skin(), - 'domain': get_server_url(), - 'site_name': get_site_name() + 'enable_public_registrations': + privileged.public_registrations('status'), + 'enable_private_mode': + privileged.private_mode('status'), + 'default_skin': + get_default_skin(), + 'domain': + get_server_url(), + 'site_name': + get_site_name() }) return initial @@ -49,10 +50,9 @@ class MediaWikiAppView(views.AppView): if new_config['password']: try: - actions.superuser_run('mediawiki', ['change-password'], - input=new_config['password'].encode()) + privileged.change_password('admin', new_config['password']) messages.success(self.request, _('Password updated')) - except ActionError as exception: + except Exception as exception: logger.exception('Failed to update password: %s', exception) messages.error( self.request, @@ -63,8 +63,7 @@ class MediaWikiAppView(views.AppView): # note action public-registration restarts, if running now if new_config['enable_public_registrations']: if not new_config['enable_private_mode']: - actions.superuser_run('mediawiki', - ['public-registrations', 'enable']) + privileged.public_registrations('enable') messages.success(self.request, _('Public registrations enabled')) else: @@ -72,21 +71,19 @@ class MediaWikiAppView(views.AppView): self.request, 'Public registrations ' + 'cannot be enabled when private mode is enabled') else: - actions.superuser_run('mediawiki', - ['public-registrations', 'disable']) + privileged.public_registrations('disable') messages.success(self.request, _('Public registrations disabled')) if is_changed('enable_private_mode'): if new_config['enable_private_mode']: - actions.superuser_run('mediawiki', ['private-mode', 'enable']) + privileged.private_mode('enable') messages.success(self.request, _('Private mode enabled')) if new_config['enable_public_registrations']: # If public registrations are enabled, then disable it - actions.superuser_run('mediawiki', - ['public-registrations', 'disable']) + privileged.public_registrations('disable') else: - actions.superuser_run('mediawiki', ['private-mode', 'disable']) + privileged.private_mode('disable') messages.success(self.request, _('Private mode disabled')) app = app_module.App.get('mediawiki') @@ -94,7 +91,7 @@ class MediaWikiAppView(views.AppView): shortcut.login_required = new_config['enable_private_mode'] if is_changed('default_skin'): - mediawiki.set_default_skin(new_config['default_skin']) + privileged.set_default_skin(new_config['default_skin']) messages.success(self.request, _('Default skin changed')) if is_changed('domain'): @@ -102,7 +99,7 @@ class MediaWikiAppView(views.AppView): messages.success(self.request, _('Domain name updated')) if is_changed('site_name'): - mediawiki.set_site_name(new_config['site_name']) + privileged.set_site_name(new_config['site_name']) messages.success(self.request, _('Site name updated')) return super().form_valid(form) From 671fb7d424d699390791a9207fe375689a9feabb Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 12:14:06 -0700 Subject: [PATCH 38/90] minetest: Use privileged decorator for actions Tests: - Functional tests work - Updating the configuration values works - Enable/disable works - Editing the max players works - Changing all of them together and one at a time Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/minetest | 96 --------------------------- plinth/modules/minetest/__init__.py | 4 +- plinth/modules/minetest/privileged.py | 45 +++++++++++++ plinth/modules/minetest/views.py | 34 +++------- 4 files changed, 56 insertions(+), 123 deletions(-) delete mode 100755 actions/minetest create mode 100644 plinth/modules/minetest/privileged.py diff --git a/actions/minetest b/actions/minetest deleted file mode 100755 index f66ef048b..000000000 --- a/actions/minetest +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Minetest server. -""" - -import argparse - -import augeas - -from plinth import action_utils - -CONFIG_FILE = '/etc/minetest/minetest.conf' -AUG_PATH = '/files' + CONFIG_FILE + '/.anon' - - -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - configure = subparsers.add_parser('configure', help='Configure Minetest') - configure.add_argument('--max_players', - help='Set maximum number of players') - configure.add_argument('--creative_mode', choices=['true', 'false'], - help='Set creative mode true/false') - configure.add_argument('--enable_pvp', choices=['true', 'false'], - help='Set player Vs player true/false') - configure.add_argument('--enable_damage', choices=['true', 'false'], - help='Set damage true/false') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_configure(arguments): - """Configure Minetest.""" - aug = load_augeas() - - if arguments.max_players: - set_max_players(aug, arguments.max_players) - if arguments.creative_mode: - set_creative_mode(aug, arguments.creative_mode) - if arguments.enable_pvp: - enable_pvp(aug, arguments.enable_pvp) - if arguments.enable_damage: - enable_damage(aug, arguments.enable_damage) - - action_utils.service_restart('minetest-server') - - -def set_max_players(aug, max_players): - """Sets the number of max players""" - aug.set(AUG_PATH + '/max_users', max_players) - aug.save() - - -def enable_pvp(aug, choice): - """Enables pvp""" - aug.set(AUG_PATH + '/enable_pvp', choice) - aug.save() - - -def set_creative_mode(aug, choice): - """Enables or disables creative mode""" - aug.set(AUG_PATH + '/creative_mode', choice) - aug.save() - - -def enable_damage(aug, choice): - """Enables damage""" - aug.set(AUG_PATH + '/enable_damage', choice) - aug.save() - - -def load_augeas(): - """Initialize Augeas.""" - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - aug.set('/augeas/load/Php/lens', 'Php.lns') - aug.set('/augeas/load/Php/incl[last() + 1]', CONFIG_FILE) - aug.load() - return aug - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/minetest/__init__.py b/plinth/modules/minetest/__init__.py index 87f112a1a..ada63c7eb 100644 --- a/plinth/modules/minetest/__init__.py +++ b/plinth/modules/minetest/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for Minetest server. -""" +"""FreedomBox app for Minetest server.""" import augeas from django.urls import reverse_lazy diff --git a/plinth/modules/minetest/privileged.py b/plinth/modules/minetest/privileged.py new file mode 100644 index 000000000..ceae1812f --- /dev/null +++ b/plinth/modules/minetest/privileged.py @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure Minetest server.""" + +from typing import Optional + +import augeas + +from plinth import action_utils +from plinth.actions import privileged + +CONFIG_FILE = '/etc/minetest/minetest.conf' +AUG_PATH = '/files' + CONFIG_FILE + '/.anon' + + +@privileged +def configure(max_players: Optional[int] = None, + enable_pvp: Optional[bool] = None, + creative_mode: Optional[bool] = None, + enable_damage: Optional[bool] = None): + """Update configuration file and restart daemon if necessary.""" + aug = load_augeas() + if max_players is not None: + aug.set(AUG_PATH + '/max_users', str(max_players)) + + if enable_pvp is not None: + aug.set(AUG_PATH + '/enable_pvp', str(enable_pvp).lower()) + + if creative_mode is not None: + aug.set(AUG_PATH + '/creative_mode', str(creative_mode).lower()) + + if enable_damage is not None: + aug.set(AUG_PATH + '/enable_damage', str(enable_damage).lower()) + + aug.save() + action_utils.service_try_restart('minetest-server') + + +def load_augeas(): + """Initialize Augeas.""" + aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + + augeas.Augeas.NO_MODL_AUTOLOAD) + aug.set('/augeas/load/Php/lens', 'Php.lns') + aug.set('/augeas/load/Php/incl[last() + 1]', CONFIG_FILE) + aug.load() + return aug diff --git a/plinth/modules/minetest/views.py b/plinth/modules/minetest/views.py index 8e9757933..dd347dc2e 100644 --- a/plinth/modules/minetest/views.py +++ b/plinth/modules/minetest/views.py @@ -1,21 +1,19 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for minetest module. -""" +"""Views for minetest module.""" from django.contrib import messages from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth.modules import names from plinth.views import AppView -from . import get_configuration +from . import get_configuration, privileged from .forms import MinetestForm class MinetestAppView(AppView): # pylint: disable=too-many-ancestors """A specialized view for configuring minetest.""" + app_id = 'minetest' template_name = 'minetest.html' form_class = MinetestForm @@ -37,35 +35,23 @@ class MinetestAppView(AppView): # pylint: disable=too-many-ancestors """Change the configurations of Minetest service.""" data = form.cleaned_data old_config = get_configuration() - updated = False + changes = {} if old_config['max_players'] != data['max_players'] \ and data['max_players'] is not None: - actions.superuser_run( - 'minetest', - ['configure', '--max_players', - str(data['max_players'])]) - updated = True + changes['max_players'] = data['max_players'] if old_config['creative_mode'] != data['creative_mode']: - value = 'true' if data['creative_mode'] else 'false' - actions.superuser_run('minetest', - ['configure', '--creative_mode', value]) - updated = True + changes['creative_mode'] = data['creative_mode'] if old_config['enable_pvp'] != data['enable_pvp']: - value = 'true' if data['enable_pvp'] else 'false' - actions.superuser_run('minetest', - ['configure', '--enable_pvp', value]) - updated = True + changes['enable_pvp'] = data['enable_pvp'] if old_config['enable_damage'] != data['enable_damage']: - value = 'true' if data['enable_damage'] else 'false' - actions.superuser_run('minetest', - ['configure', '--enable_damage', value]) - updated = True + changes['enable_damage'] = data['enable_damage'] - if updated: + if changes: + privileged.configure(**changes) messages.success(self.request, _('Configuration updated')) return super().form_valid(form) From 9747051a8b02f4b73a75cee1bd64c5273269ed26 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 14:53:13 -0700 Subject: [PATCH 39/90] minidlna: Use privileged decorator for actions Tests: - Functional tests work - Setting the media directory updates the configuration file. Newly set directory is shown on the app page after update. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/minidlna/__init__.py | 24 ++---- .../modules/minidlna/privileged.py | 73 ++++++------------- plinth/modules/minidlna/views.py | 18 ++--- 3 files changed, 38 insertions(+), 77 deletions(-) rename actions/minidlna => plinth/modules/minidlna/privileged.py (58%) mode change 100755 => 100644 diff --git a/plinth/modules/minidlna/__init__.py b/plinth/modules/minidlna/__init__.py index 8dc6c462b..a08639517 100644 --- a/plinth/modules/minidlna/__init__.py +++ b/plinth/modules/minidlna/__init__.py @@ -4,7 +4,6 @@ FreedomBox app to configure minidlna. """ from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.daemon import Daemon @@ -15,7 +14,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages, install from plinth.utils import Version -from . import manifest +from . import manifest, privileged _description = [ _('MiniDLNA is a simple media server software, with the aim of being ' @@ -30,13 +29,14 @@ _description = [ class MiniDLNAApp(app_module.App): - """Freedombox app managing miniDlna""" + """Freedombox app managing miniDlna.""" + app_id = 'minidlna' _version = 2 def __init__(self): - """Initialize the app components""" + """Initialize the app components.""" super().__init__() groups = {'minidlna': _('Media streaming server')} @@ -92,7 +92,7 @@ class MiniDLNAApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('minidlna', ['setup']) + privileged.setup() if not old_version: self.enable() @@ -106,18 +106,8 @@ class MiniDLNAApp(app_module.App): if Version(package['new_version']) > Version('1.4~'): return False - media_dir = get_media_dir() + media_dir = privileged.get_media_dir() install(['minidlna'], force_configuration='new') - set_media_dir(media_dir) + privileged.set_media_dir(media_dir) return True - - -def get_media_dir(): - """Return the currently set media directory.""" - return actions.superuser_run('minidlna', ['get-media-dir']) - - -def set_media_dir(media_dir): - """Set the media directory from which files will be scanned for sharing.""" - actions.superuser_run('minidlna', ['set-media-dir', '--dir', media_dir]) diff --git a/actions/minidlna b/plinth/modules/minidlna/privileged.py old mode 100755 new mode 100644 similarity index 58% rename from actions/minidlna rename to plinth/modules/minidlna/privileged.py index e742c52af..2fba83493 --- a/actions/minidlna +++ b/plinth/modules/minidlna/privileged.py @@ -1,9 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration actions for the minidlna server. -""" -import argparse +"""Configure minidlna server.""" + import subprocess from os import chmod, fdopen, remove, stat from shutil import move @@ -12,6 +9,7 @@ from tempfile import mkstemp import augeas from plinth import action_utils +from plinth.actions import privileged from plinth.utils import grep CONFIG_PATH = '/etc/minidlna.conf' @@ -22,23 +20,6 @@ fs.inotify.max_user_watches = 100000 ''' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Setup SSH server') - - subparsers.add_parser('get-media-dir', help='Get media directory') - - set_media_dir = subparsers.add_parser('set-media-dir', - help='Set custom media directory') - set_media_dir.add_argument('--dir') - - subparsers.required = True - return parser.parse_args() - - def _undo_old_configuration_changes(): """Restore /etc/sysctl.conf to before our changes. @@ -59,10 +40,11 @@ def _undo_old_configuration_changes(): aug.save() -def subcommand_setup(_): - """ - Increase inotify watches per folder to allow minidlna to - monitor changes in large media-dirs. +@privileged +def setup(): + """Increase inotify watches per folder. + + This is to allow minidlna to monitor changes in large media-dirs. """ _undo_old_configuration_changes() with open('/etc/sysctl.d/50-freedombox-minidlna.conf', 'w', @@ -72,29 +54,31 @@ def subcommand_setup(_): subprocess.run(['systemctl', 'restart', 'systemd-sysctl'], check=True) -def subcommand_get_media_dir(_): - """Retrieve media directory from minidlna.conf""" +@privileged +def get_media_dir() -> str: + """Retrieve media directory from minidlna.conf.""" line = grep('^media_dir=', CONFIG_PATH) - - print(line[0].split("=")[1]) + return line[0].split('=')[1] -def subcommand_set_media_dir(arguments): - """Set media directory in minidlna.conf""" +@privileged +def set_media_dir(media_dir: str): + """Set media directory in minidlna.conf.""" line = grep('^media_dir=', CONFIG_PATH)[0] - new_line = 'media_dir=%s\n' % arguments.dir + new_line = 'media_dir=%s\n' % media_dir replace_in_config_file(CONFIG_PATH, line, new_line) if action_utils.service_is_running('minidlna'): action_utils.service_restart('minidlna') def replace_in_config_file(file_path, pattern, subst): - """ - Create a temporary minidlna.conf file, - replace the media dir config, - remove original one and move the temporary file. - Preserve permissions as the original file. + """Replace a directive in configuration file. + + - Create a temporary minidlna.conf file + - Replace the media dir config + - Remove original one and move the temporary file + - Preserve permissions as the original file """ temp_file, temp_file_path = mkstemp() with fdopen(temp_file, 'w') as new_file: @@ -106,16 +90,3 @@ def replace_in_config_file(file_path, pattern, subst): remove(file_path) move(temp_file_path, file_path) chmod(file_path, old_st_mode) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/minidlna/views.py b/plinth/modules/minidlna/views.py index 91c24a55c..16f58fdfa 100644 --- a/plinth/modules/minidlna/views.py +++ b/plinth/modules/minidlna/views.py @@ -1,31 +1,31 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the minidlna module -""" +"""Views for the minidlna module.""" + import os from django.contrib import messages from django.utils.translation import gettext_lazy as _ -from plinth.modules import minidlna from plinth.views import AppView +from . import privileged from .forms import MiniDLNAServerForm class MiniDLNAAppView(AppView): + """Show minidlna app view.""" + app_id = 'minidlna' form_class = MiniDLNAServerForm def get_initial(self): - """Initial form value as found in the minidlna.conf""" + """Return initial values of the form.""" initial = super().get_initial() - initial.update({'media_dir': minidlna.get_media_dir()}) - + initial.update({'media_dir': privileged.get_media_dir()}) return initial def form_valid(self, form): - """Apply changes from the form""" + """Apply changes from the form.""" old_config = form.initial new_config = form.cleaned_data @@ -34,7 +34,7 @@ class MiniDLNAAppView(AppView): messages.error(self.request, _('Specified directory does not exist.')) else: - minidlna.set_media_dir(new_config['media_dir']) + privileged.set_media_dir(new_config['media_dir']) messages.success(self.request, _('Updated media directory')) return super().form_valid(form) From f7ce8a7c668211fb9138b9a5579f6d60ad819633 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 28 Sep 2022 23:41:56 -0700 Subject: [PATCH 40/90] minidlna: Use the exposed URL for diagnostic test This prevents the diagnostic failure. Tests: - Functional tests pass - Diagnostics page shows a test for each hostname in the system. All of them pass. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/minidlna/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plinth/modules/minidlna/__init__.py b/plinth/modules/minidlna/__init__.py index a08639517..e378d8d3b 100644 --- a/plinth/modules/minidlna/__init__.py +++ b/plinth/modules/minidlna/__init__.py @@ -75,7 +75,7 @@ class MiniDLNAApp(app_module.App): self.add(firewall) webserver = Webserver('webserver-minidlna', 'minidlna-freedombox', - urls=['http://localhost:8200/']) + urls=['https://{host}/_minidlna/']) self.add(webserver) daemon = Daemon('daemon-minidlna', 'minidlna') From 4dda9ad6b9033599746a9370dd6ba06128379ccc Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 12:23:09 -0700 Subject: [PATCH 41/90] networks: Use privileged decorator for actions Tests: - Initial setup of during first setup works - When there are no wired network interfaces - When there is 1 wired network interface - When there is one wifi interface. wired network is setup as 'external' WAN. (simulated with edit of _get_interfaces()) - When there are no wifi interfaces. wired network is setup as 'internal' WAN. - When there are multiple wired network interfaces - First one is setup as WAN rest as shared - When there is one wifi interface, interface is setup as shared. - When there are no wifi interfaces Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- .gitlab-ci.yml | 2 +- actions/networks | 161 --------------- plinth/modules/networks/__init__.py | 9 +- plinth/modules/networks/privileged.py | 189 ++++++++++++++++++ .../modules/networks/tests/test_privileged.py | 28 +++ 5 files changed, 222 insertions(+), 167 deletions(-) delete mode 100755 actions/networks create mode 100644 plinth/modules/networks/privileged.py create mode 100644 plinth/modules/networks/tests/test_privileged.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ed2d2aa2b..11b5f5a42 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ code-quality: stage: test needs: [] script: - - python3 -m flake8 --exclude actions/networks container plinth actions/* + - python3 -m flake8 container plinth actions/* unit-tests: stage: test diff --git a/actions/networks b/actions/networks deleted file mode 100755 index 7616e598a..000000000 --- a/actions/networks +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/bash - -set -e - -# Configure networking for all wired and wireless devices. -# -# Creates network-manager connections. - -function get-interfaces { - WIRED_IFACES=$(nmcli --terse --fields type,device device | grep "^ethernet:" | cut -d: -f2 | sort -V) - NO_OF_WIRED_IFACES=$(echo $WIRED_IFACES | wc -w) - - WIRELESS_IFACES=$(nmcli --terse --fields type,device device | grep "^wifi:" | cut -d: -f2 | sort -V) - NO_OF_WIRELESS_IFACES=$(echo $WIRELESS_IFACES | wc -w) -} - -function add-connection { - local connection_name="$1" - shift - local interface="$1" - shift - local remaining_arguments="$@" - - already_exists=$(nmcli --terse --fields name,device con show | grep "$connection_name:$interface" || true) - if [ -n "$already_exists" ]; then - echo "Connection '$connection_name' already exists for device '$interface', not adding." - else - nmcli con add con-name "$connection_name" ifname "$interface" $remaining_arguments - fi -} - -function activate-connection { - connection_name="$1" - nohup nmcli con up "$connection_name" &>/dev/null & -} - -function configure-regular-interface { - local interface="$1" - local zone="$2" - local connection_name="FreedomBox WAN" - - # Create n-m connection for a regular interface - add-connection "$connection_name" "$interface" type ethernet - nmcli con modify "$connection_name" connection.autoconnect TRUE - nmcli con modify "$connection_name" connection.zone "$zone" - activate-connection "$connection_name" - - echo "Configured interface '$interface' for '$zone' use as '$connection_name'." -} - -function configure-shared-interface { - local interface="$1" - local connection_name="FreedomBox LAN $interface" - - # Create n-m connection for eth1 - add-connection "$connection_name" "$interface" type ethernet - nmcli con modify "$connection_name" connection.autoconnect TRUE - nmcli con modify "$connection_name" connection.zone internal - - # Configure this interface to be shared with other computers. - # - Self-assign an address and network - # - Start and manage DNS server (dnsmasq) - # - Start and manage DHCP server (dnsmasq) - # - Register address with mDNS - # - Add firewall rules for NATing from this interface - nmcli con modify "$connection_name" ipv4.method shared - - activate-connection "$connection_name" - - echo "Configured interface '$interface' for shared use as '$connection_name'." -} - -function configure-wireless-interface { - local interface="$1" - local connection_name="FreedomBox $interface" - local ssid="FreedomBox$interface" - local secret="freedombox123" - - add-connection "$connection_name" "$interface" type wifi ssid "$ssid" - nmcli con modify "$connection_name" connection.autoconnect TRUE - nmcli con modify "$connection_name" connection.zone internal - nmcli con modify "$connection_name" ipv4.method shared - nmcli con modify "$connection_name" wifi.mode ap - nmcli con modify "$connection_name" wifi-sec.key-mgmt wpa-psk - nmcli con modify "$connection_name" wifi-sec.psk "$secret" - activate-connection "$connection_name" - - echo "Configured interface '$interface' for shared use as '$connection_name'." -} - -function multi-wired-setup { - local first_interface="$1" - shift - local remaining_interfaces="$@" - - configure-regular-interface "$first_interface" external - - for interface in $remaining_interfaces - do - configure-shared-interface "$interface" - done -} - -function one-wired-setup { - local interface="$1" - - case $NO_OF_WIRELESS_IFACES in - "0") - configure-regular-interface "$interface" internal - ;; - *) - configure-regular-interface "$interface" external - ;; - esac -} - -function wireless-setup { - local interfaces="$@" - - for interface in $interfaces - do - configure-wireless-interface "$interface" - done -} - -function setup { - echo "Setting up network configuration..." - get-interfaces - - case $NO_OF_WIRED_IFACES in - "0") - echo "No wired interfaces detected." - ;; - "1") - one-wired-setup $WIRED_IFACES - ;; - *) - multi-wired-setup $WIRED_IFACES - esac - - wireless-setup $WIRELESS_IFACES - - echo "Done setting up network configuration." -} - -# -# For a user who installed using freedombox-setup Debian package, when -# FreedomBox Service (Plinth) is run for the first time, don't run network -# setup. This is ensured by checking for the file -# /var/lib/freedombox/is-freedombox-disk-image which will not exist. -# -# For a user who installed using FreedomBox disk image, when FreedomBox Service -# (Plinth) runs for the first time, setup process executes and triggers the -# script due networks module being an essential module. -# -if [ -f "/var/lib/freedombox/is-freedombox-disk-image" ] -then - setup -else - echo "Not a FreedomBox disk image. Skipping network configuration." -fi diff --git a/plinth/modules/networks/__init__.py b/plinth/modules/networks/__init__.py index 3e7252428..6bda322df 100644 --- a/plinth/modules/networks/__init__.py +++ b/plinth/modules/networks/__init__.py @@ -1,18 +1,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to interface with network-manager. -""" +"""FreedomBox app to interface with network-manager.""" import subprocess from logging import Logger from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import daemon, kvstore, menu, network from plinth.package import Packages +from . import privileged + first_boot_steps = [ { 'id': 'network_topology_wizard', @@ -83,7 +82,7 @@ class NetworksApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('networks') + privileged.setup() self.enable() diff --git a/plinth/modules/networks/privileged.py b/plinth/modules/networks/privileged.py new file mode 100644 index 000000000..2ea77518e --- /dev/null +++ b/plinth/modules/networks/privileged.py @@ -0,0 +1,189 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure network manager. + +During initial setup, configure networking for all wired and wireless devices +by creating network manager connections. +""" + +import collections +import itertools +import logging +import re +import subprocess + +from plinth import action_utils +from plinth.actions import privileged + + +def _sort_interfaces(interfaces: list[str]) -> list[str]: + """Sort interfaces in a well-defined way: eth0, eth1, eth2, ... eth10.""" + + def key_func(interface): + parts = re.findall(r'(\D*)(\d*)', interface) + parts = [(string, int(number) if number else number) + for string, number in parts] + return list(itertools.chain(parts)) + + return sorted(interfaces, key=key_func) + + +def _get_interfaces() -> dict[str, list[str]]: + """Return all network interfaces by their type.""" + output = subprocess.check_output( + ['nmcli', '--terse', '--fields', 'type,device', 'device']) + interfaces = collections.defaultdict(list) + for line in output.decode().splitlines(): + type_, _, interface = line.partition(':') + interfaces[type_].append(interface) + + for type_ in interfaces: + interfaces[type_] = _sort_interfaces(interfaces[type_]) + + return interfaces + + +def _add_connection(connection_name: str, interface: str, + remaining_arguments: list[str]): + """Add an Ethernet/Wi-Fi connection of type regular or shared.""" + output = subprocess.check_output( + ['nmcli', '--terse', '--fields', 'name,device', 'con', 'show']) + lines = output.decode().splitlines() + if f'{connection_name}:{interface}' in lines: + logging.info('Connection %s already exists for device %s, not adding.', + connection_name, interface) + else: + subprocess.run([ + 'nmcli', 'con', 'add', 'con-name', connection_name, 'ifname', + interface + ] + remaining_arguments, check=True) + + +def _activate_connection(connection_name: str): + """Activate a network connection in a background process.""" + subprocess.Popen(['nohup', 'nmcli', 'con', 'up', connection_name], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def _configure_regular_interface(interface: str, zone: str): + """Create a connection that is not a shared connection.""" + connection_name = 'FreedomBox WAN' + properties = {'connection.autoconnect': 'TRUE', 'connection.zone': zone} + + # Create n-m connection for a regular interface + _add_connection(connection_name, interface, ['type', 'ethernet']) + _set_connection_properties(connection_name, properties) + _activate_connection(connection_name) + + logging.info('Configured interface %s for %s use as %s.', interface, zone, + connection_name) + + +def _configure_shared_interface(interface: str): + """Create a shared connection that has traffic forwarding enabled. + + Shared connection means: + - Self-assign an address and network + - Start and manage DNS server (dnsmasq) + - Start and manage DHCP server (dnsmasq) + - Register address with mDNS + - Add firewall rules for NATing from this interface + """ + connection_name = f'FreedomBox LAN {interface}' + properties = { + 'connection.autoconnect': 'TRUE', + 'connection.zone': 'internal', + 'ipv4.method': 'shared' + } + + # Create n-m connection for eth1 + _add_connection(connection_name, interface, ['type', 'ethernet']) + _set_connection_properties(connection_name, properties) + _activate_connection(connection_name) + + logging.info('Configured interface %s for shared use as %s.', interface, + connection_name) + + +def _set_connection_properties(connection_name: str, properties: dict[str, + str]): + """Configure property key/values on a connection.""" + for key, value in properties.items(): + subprocess.run(['nmcli', 'con', 'modify', connection_name, key, value], + check=True) + + +def _configure_wireless_interface(interface: str): + """Configure a wireless access point.""" + connection_name = f'FreedomBox {interface}' + ssid = f'FreedomBox{interface}' + secret = 'freedombox123' + properties = { + 'connection.autoconnect': 'TRUE', + 'connection.zone': 'internal', + 'ipv4.method': 'shared', + 'wifi.mode': 'ap', + 'wifi-sec.key-mgmt': 'wpa-psk', + 'wifi-sec.psk': secret + } + + _add_connection(connection_name, interface, ['type', 'wifi', 'ssid', ssid]) + _set_connection_properties(connection_name, properties) + _activate_connection(connection_name) + + logging.info('Configured interface %s for shared use as %s', interface, + connection_name) + + +def _multi_wired_setup(interfaces: list[str]): + """Configure all Ethernet connections on a system with many of them.""" + _configure_regular_interface(interfaces[0], 'external') + + for interface in interfaces[1:]: + _configure_shared_interface(interface) + + +def _one_wired_setup(interface: str, interfaces: dict[str, list[str]]): + """Configure an Ethernet connection on a system with only one.""" + if not len(interfaces['wifi']): + _configure_regular_interface(interface, 'internal') + else: + _configure_regular_interface(interface, 'external') + + +def _wireless_setup(interfaces: list[str]): + """Configure all wireless access points.""" + for interface in interfaces: + _configure_wireless_interface(interface) + + +@privileged +def setup(): + """Create network manager connections. + + For a user who installed using freedombox-setup Debian package, when + FreedomBox Service (Plinth) is run for the first time, don't run network + setup. This is ensured by checking for the file + /var/lib/freedombox/is-freedombox-disk-image which will not exist. + + For a user who installed using FreedomBox disk image, when FreedomBox + Service (Plinth) runs for the first time, setup process executes and + triggers the script due networks module being an essential module. + """ + if not action_utils.is_disk_image(): + logging.info( + 'Not a FreedomBox disk image. Skipping network configuration.') + return + + logging.info('Setting up network configuration...') + interfaces = _get_interfaces() + + if len(interfaces['ethernet']) == 0: + logging.info('No wired interfaces detected.') + elif len(interfaces['ethernet']) == 1: + _one_wired_setup(interfaces['ethernet'][0], interfaces) + else: + _multi_wired_setup(interfaces['ethernet']) + + _wireless_setup(interfaces['wifi']) + + logging.info('Done setting up network configuration.') diff --git a/plinth/modules/networks/tests/test_privileged.py b/plinth/modules/networks/tests/test_privileged.py new file mode 100644 index 000000000..b18de501e --- /dev/null +++ b/plinth/modules/networks/tests/test_privileged.py @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Test privileged method for networks app.""" + +from unittest.mock import patch + +from .. import privileged + + +@patch('subprocess.check_output') +def test_get_interfaces(check_output): + """Test returning list of network interfaces in sorted order.""" + check_output.return_value = '\n'.join([ + 'ethernet:ve-fbx-testing', + 'ethernet:enp39s0', + 'ethernet:enp32s1', + 'ethernet:enp4s1', + 'bridge:virbr0', + 'wifi:wlp41s0', + 'loopback:lo', + ]).encode() + + interfaces = privileged._get_interfaces() + assert interfaces == { + 'ethernet': ['enp4s1', 'enp32s1', 'enp39s0', 've-fbx-testing'], + 'bridge': ['virbr0'], + 'wifi': ['wlp41s0'], + 'loopback': ['lo'] + } From e3d4811f5ed18d0641e6e416531974a95f93ea8f Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 15:05:09 -0700 Subject: [PATCH 42/90] openvpn: Use privileged decorator for actions Tests: - Functional tests pass. - Initial setup completes successfully and does not take very long time. - Profiles can be downloaded successfully and imported. - A client an use them to connect. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/openvpn/__init__.py | 18 ++--- .../modules/openvpn/privileged.py | 67 ++++--------------- .../openvpn/tests/test_configuration.py | 36 +++++----- plinth/modules/openvpn/views.py | 23 +++---- 4 files changed, 47 insertions(+), 97 deletions(-) rename actions/openvpn => plinth/modules/openvpn/privileged.py (81%) mode change 100755 => 100644 diff --git a/plinth/modules/openvpn/__init__.py b/plinth/modules/openvpn/__init__.py index 4ec97d813..93b09dd3e 100644 --- a/plinth/modules/openvpn/__init__.py +++ b/plinth/modules/openvpn/__init__.py @@ -1,14 +1,11 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure OpenVPN server. -""" +"""FreedomBox app to configure OpenVPN server.""" import os from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -18,7 +15,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ format_lazy( @@ -44,7 +41,7 @@ class OpenVPNApp(app_module.App): @property def can_be_disabled(self): """Return whether the app can be disabled.""" - return is_setup() + return privileged.is_setup() def __init__(self): """Create components for the app.""" @@ -102,20 +99,15 @@ class OpenVPNApp(app_module.App): Return True when there are no leader components and OpenVPN setup is done. """ - return super().is_enabled() and is_setup() + return super().is_enabled() and privileged.is_setup() def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('openvpn', ['setup']) + privileged.setup() self.enable() -def is_setup(): - """Return whether the service is running.""" - return actions.superuser_run('openvpn', ['is-setup']).strip() == 'true' - - def is_using_ecc(): """Return whether the service is using ECC.""" if os.path.exists(SERVER_CONFIGURATION_FILE): diff --git a/actions/openvpn b/plinth/modules/openvpn/privileged.py old mode 100755 new mode 100644 similarity index 81% rename from actions/openvpn rename to plinth/modules/openvpn/privileged.py index 088995bc5..85682ae32 --- a/actions/openvpn +++ b/plinth/modules/openvpn/privileged.py @@ -1,16 +1,13 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for OpenVPN server. -""" +"""Configure OpenVPN server.""" -import argparse import os import subprocess import augeas from plinth import action_utils +from plinth.actions import privileged KEYS_DIRECTORY = '/etc/openvpn/freedombox-keys' @@ -120,24 +117,6 @@ CERTIFICATE_CONFIGURATION_ECC = { COMMON_ARGS = {'env': CERTIFICATE_CONFIGURATION_ECC, 'cwd': KEYS_DIRECTORY} -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('is-setup', help='Return whether setup is completed') - subparsers.add_parser('setup', help='Setup OpenVPN server configuration') - - get_profile = subparsers.add_parser( - 'get-profile', help='Return the OpenVPN profile of a user') - get_profile.add_argument('username', help='User to get profile for') - get_profile.add_argument('remote_server', - help='The server name for the user to connect') - - subparsers.required = True - return parser.parse_args() - - def _is_using_ecc(): """Return whether the service is using ECC.""" if os.path.exists(SERVER_CONFIGURATION_PATH): @@ -149,17 +128,14 @@ def _is_using_ecc(): return False -def _is_setup(): +@privileged +def is_setup() -> bool: """Return whether setup is complete.""" return _is_non_empty_file(DH_PARAMS) or os.path.exists(EC_PARAMS_DIR) -def subcommand_is_setup(_): - """Print whether setup is complete.""" - print('true' if _is_setup() else 'false') - - -def subcommand_setup(_): +@privileged +def setup(): """Setup configuration, CA and certificates.""" _write_server_config() _create_certificates() @@ -236,11 +212,9 @@ def _create_certificates(): **COMMON_ARGS) -def subcommand_get_profile(arguments): +@privileged +def get_profile(username: str, remote_server: str) -> str: """Return the profile for a user.""" - username = arguments.username - remote_server = arguments.remote_server - if username == 'ca' or username == 'server': raise Exception('Invalid username') @@ -264,16 +238,14 @@ def subcommand_get_profile(arguments): client_configuration = CLIENT_CONFIGURATION_ECC if _is_using_ecc( ) else CLIENT_CONFIGURATION_RSA - profile = client_configuration.format(ca=ca_string, - cert=user_certificate_string, - key=user_key_string, - remote=remote_server) - - print(profile) + return client_configuration.format(ca=ca_string, + cert=user_certificate_string, + key=user_key_string, + remote=remote_server) def set_unique_subject(value): - """ Sets the unique_subject value to a particular value""" + """Set the unique_subject value to a particular value.""" aug = load_augeas() aug.set('/files' + ATTR_FILE + '/unique_subject', value) aug.save() @@ -300,16 +272,3 @@ def load_augeas(): aug.set('/augeas/load/Simplevars/incl[last() + 1]', ATTR_FILE) aug.load() return aug - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/openvpn/tests/test_configuration.py b/plinth/modules/openvpn/tests/test_configuration.py index 35dd75d1a..11f8e8cee 100644 --- a/plinth/modules/openvpn/tests/test_configuration.py +++ b/plinth/modules/openvpn/tests/test_configuration.py @@ -9,8 +9,10 @@ from unittest.mock import patch import pytest from plinth.modules import openvpn +from plinth.modules.openvpn import privileged -actions_name = 'openvpn' +pytestmark = pytest.mark.usefixtures('mock_privileged') +privileged_modules_to_mock = ['plinth.modules.openvpn.privileged'] @pytest.fixture(name='keys_directory') @@ -19,10 +21,10 @@ def fixture_keys_directory(tmp_path): @pytest.fixture(autouse=True) -def fixture_set_keys_directory(actions_module, keys_directory): +def fixture_set_keys_directory(keys_directory): """Set the keys directory in the actions module.""" - actions_module.DH_PARAMS = f'{keys_directory}/pki/dh.pem' - actions_module.EC_PARAMS_DIR = f'{keys_directory}/pki/ecparams' + privileged.DH_PARAMS = f'{keys_directory}/pki/dh.pem' + privileged.EC_PARAMS_DIR = f'{keys_directory}/pki/ecparams' @pytest.fixture(name='conf_file') @@ -47,21 +49,19 @@ def test_identify_ecc_configuration(conf_file): assert openvpn.is_using_ecc() -def test_is_setup_with_rsa(keys_directory, call_action): +def test_is_setup_with_rsa(keys_directory): """is_setup should work with RSA configuration.""" - with patch('plinth.actions.superuser_run', call_action): - (keys_directory / 'pki').mkdir() - dh_params_file = keys_directory / 'pki' / 'dh.pem' - dh_params_file.write_text('some content') - assert openvpn.is_setup() - os.remove(dh_params_file) + (keys_directory / 'pki').mkdir() + dh_params_file = keys_directory / 'pki' / 'dh.pem' + dh_params_file.write_text('some content') + assert privileged.is_setup() + os.remove(dh_params_file) -def test_is_setup_with_ecc(keys_directory, call_action): +def test_is_setup_with_ecc(keys_directory): """is_setup should work with RSA configuration.""" - with patch('plinth.actions.superuser_run', call_action): - (keys_directory / 'pki' / 'ecparams').mkdir(parents=True) - ec_params_file = keys_directory / 'pki' / 'ecparams' / 'somecurve.pem' - ec_params_file.write_text('some content') - assert openvpn.is_setup() - os.remove(ec_params_file) + (keys_directory / 'pki' / 'ecparams').mkdir(parents=True) + ec_params_file = keys_directory / 'pki' / 'ecparams' / 'somecurve.pem' + ec_params_file.write_text('some content') + assert privileged.is_setup() + os.remove(ec_params_file) diff --git a/plinth/modules/openvpn/views.py b/plinth/modules/openvpn/views.py index 903093bd6..f64ff29c1 100644 --- a/plinth/modules/openvpn/views.py +++ b/plinth/modules/openvpn/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring OpenVPN server. -""" +"""FreedomBox app for configuring OpenVPN server.""" import logging @@ -9,16 +7,18 @@ from django.http import HttpResponse from django.shortcuts import redirect from django.views.decorators.http import require_POST -from plinth import actions from plinth import app as app_module from plinth.modules import config, openvpn from plinth.views import AppView +from . import privileged + logger = logging.getLogger(__name__) class OpenVPNAppView(AppView): """Show OpenVPN app main page.""" + app_id = 'openvpn' template_name = 'openvpn.html' @@ -26,7 +26,7 @@ class OpenVPNAppView(AppView): """Add additional context data for template.""" context = super().get_context_data(*args, **kwargs) context['status'] = { - 'is_setup': openvpn.is_setup(), + 'is_setup': privileged.is_setup(), } context['using_ecc'] = openvpn.is_using_ecc() return context @@ -35,8 +35,8 @@ class OpenVPNAppView(AppView): @require_POST def setup(_): """Start the setup process.""" - if not openvpn.is_setup(): - actions.superuser_run('openvpn', ['setup'], run_in_background=True) + if not privileged.is_setup(): + privileged.setup() app_module.App.get('openvpn').enable() @@ -51,9 +51,7 @@ def profile(request): if not config.get_domainname(): domainname = config.get_hostname() - profile_string = actions.superuser_run( - 'openvpn', ['get-profile', username, domainname]) - + profile_string = privileged.get_profile(username, domainname) response = HttpResponse(profile_string, content_type='application/x-openvpn-profile') response['Content-Disposition'] = \ @@ -65,6 +63,7 @@ def profile(request): @require_POST def ecc(_): """Migrate from RSA to ECC.""" - if openvpn.is_setup(): - actions.superuser_run('openvpn', ['setup'], run_in_background=True) + if privileged.is_setup(): + privileged.setup() + return redirect('openvpn:index') From 8f672cd49b753ea0889e24fff6614b07d68a2dee Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 29 Sep 2022 10:57:17 -0700 Subject: [PATCH 43/90] openvpn: Drop RSA to ECC migration code and two-step setup - RSA to ECC migration was introduced in October 2020 is available to Buster (via backports) and to Bullseye users. Dropping the code will make it easy to test regular maintenance code updates. - A two step setup process of first installing and then setting up the certificates is no longer necessary. (New installs already don't use this). The certificate generation process does not take hours but minutes. We also have a good progress indication during install+setup process. Tests: - Functional tests pass. - Initial setup completes successfully and does not take very long time. - Profiles can be downloaded successfully and imported. - A client an use them to connect. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/openvpn/__init__.py | 26 ------- plinth/modules/openvpn/privileged.py | 60 ++--------------- .../openvpn/templates/migrate_to_ecc.html | 39 ----------- plinth/modules/openvpn/templates/openvpn.html | 58 ++++++---------- .../openvpn/tests/test_configuration.py | 67 ------------------- plinth/modules/openvpn/urls.py | 6 +- plinth/modules/openvpn/views.py | 34 +--------- 7 files changed, 27 insertions(+), 263 deletions(-) delete mode 100644 plinth/modules/openvpn/templates/migrate_to_ecc.html delete mode 100644 plinth/modules/openvpn/tests/test_configuration.py diff --git a/plinth/modules/openvpn/__init__.py b/plinth/modules/openvpn/__init__.py index 93b09dd3e..832723573 100644 --- a/plinth/modules/openvpn/__init__.py +++ b/plinth/modules/openvpn/__init__.py @@ -1,8 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later """FreedomBox app to configure OpenVPN server.""" -import os - from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ @@ -38,11 +36,6 @@ class OpenVPNApp(app_module.App): _version = 4 - @property - def can_be_disabled(self): - """Return whether the app can be disabled.""" - return privileged.is_setup() - def __init__(self): """Create components for the app.""" super().__init__() @@ -93,27 +86,8 @@ class OpenVPNApp(app_module.App): **manifest.backup) self.add(backup_restore) - def is_enabled(self): - """Return whether all the leader components are enabled. - - Return True when there are no leader components and OpenVPN setup - is done. - """ - return super().is_enabled() and privileged.is_setup() - def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) privileged.setup() self.enable() - - -def is_using_ecc(): - """Return whether the service is using ECC.""" - if os.path.exists(SERVER_CONFIGURATION_FILE): - with open(SERVER_CONFIGURATION_FILE, 'r', - encoding='utf-8') as file_handle: - for line in file_handle: - if line.strip() == 'dh none': - return True - return False diff --git a/plinth/modules/openvpn/privileged.py b/plinth/modules/openvpn/privileged.py index 85682ae32..e33c7c541 100644 --- a/plinth/modules/openvpn/privileged.py +++ b/plinth/modules/openvpn/privileged.py @@ -50,26 +50,7 @@ cipher AES-256-CBC script-security 2 ''' -CLIENT_CONFIGURATION_RSA = ''' -client -remote {remote} 1194 -proto udp -proto udp6 -dev tun -nobind -remote-cert-tls server -cipher AES-256-CBC -comp-lzo -redirect-gateway -verb 3 - -{ca} - -{cert} - -{key}''' - -CLIENT_CONFIGURATION_ECC = ''' +CLIENT_CONFIGURATION = ''' client remote {remote} 1194 proto udp @@ -88,6 +69,7 @@ verb 3 {key}''' CERTIFICATE_CONFIGURATION = { + 'EASYRSA_ALGO': 'ec', 'EASYRSA_BATCH': '1', 'EASYRSA_DIGEST': 'sha512', 'KEY_CONFIG': '/usr/share/easy-rsa/openssl-easyrsa.cnf', @@ -104,34 +86,7 @@ CERTIFICATE_CONFIGURATION = { 'EASYRSA_REQ_NAME': 'FreedomBox' } -CERTIFICATE_CONFIGURATION_RSA = { - 'EASYRSA_KEY_SIZE': '4096', - **CERTIFICATE_CONFIGURATION -} - -CERTIFICATE_CONFIGURATION_ECC = { - 'EASYRSA_ALGO': 'ec', - **CERTIFICATE_CONFIGURATION -} - -COMMON_ARGS = {'env': CERTIFICATE_CONFIGURATION_ECC, 'cwd': KEYS_DIRECTORY} - - -def _is_using_ecc(): - """Return whether the service is using ECC.""" - if os.path.exists(SERVER_CONFIGURATION_PATH): - with open(SERVER_CONFIGURATION_PATH, 'r', - encoding='utf-8') as file_handle: - for line in file_handle: - if line.strip() == 'dh none': - return True - return False - - -@privileged -def is_setup() -> bool: - """Return whether setup is complete.""" - return _is_non_empty_file(DH_PARAMS) or os.path.exists(EC_PARAMS_DIR) +COMMON_ARGS = {'env': CERTIFICATE_CONFIGURATION, 'cwd': KEYS_DIRECTORY} @privileged @@ -227,18 +182,13 @@ def get_profile(username: str, remote_server: str) -> str: subprocess.check_call([ '/usr/share/easy-rsa/easyrsa', 'build-client-full', username, 'nopass' - ], env=CERTIFICATE_CONFIGURATION_ECC if _is_using_ecc() else - CERTIFICATE_CONFIGURATION_RSA, - cwd=KEYS_DIRECTORY) + ], env=CERTIFICATE_CONFIGURATION, cwd=KEYS_DIRECTORY) user_certificate_string = _read_file(user_certificate) user_key_string = _read_file(user_key) ca_string = _read_file(CA_CERTIFICATE_PATH) - client_configuration = CLIENT_CONFIGURATION_ECC if _is_using_ecc( - ) else CLIENT_CONFIGURATION_RSA - - return client_configuration.format(ca=ca_string, + return CLIENT_CONFIGURATION.format(ca=ca_string, cert=user_certificate_string, key=user_key_string, remote=remote_server) diff --git a/plinth/modules/openvpn/templates/migrate_to_ecc.html b/plinth/modules/openvpn/templates/migrate_to_ecc.html deleted file mode 100644 index 8f22afab1..000000000 --- a/plinth/modules/openvpn/templates/migrate_to_ecc.html +++ /dev/null @@ -1,39 +0,0 @@ -{% comment %} -# SPDX-License-Identifier: AGPL-3.0-or-later -{% endcomment %} - -{% load i18n %} - -

{% trans "Migrate to ECC" %}

- -

- {% blocktrans trimmed %} - Your OpenVPN installation is currently using RSA. Switching to the - modern Elliptic Curve Cryptography improves speed of establishing a - connection and security. This operation is irreversible. It should only take - a few minutes on most single board computers. - {% endblocktrans %} -

- -

- {% blocktrans trimmed %} - All new installations of OpenVPN on {{ box_name }} will - use ECC by default. We recommend migrating as soon as possible. - {% endblocktrans %} -

- -

- {% blocktrans trimmed %} - Warning: Existing client profiles will be invalidated by this operation. All - OpenVPN users on {{ box_name }} must download their new profiles. OpenVPN - clients compatible with ECC should be used to connect to this server. - {% endblocktrans %} -

- -
- {% csrf_token %} - - -
diff --git a/plinth/modules/openvpn/templates/openvpn.html b/plinth/modules/openvpn/templates/openvpn.html index 62a42c3e8..6c2d8a4cb 100644 --- a/plinth/modules/openvpn/templates/openvpn.html +++ b/plinth/modules/openvpn/templates/openvpn.html @@ -7,49 +7,31 @@ {% load i18n %} {% load static %} -{% block status %} - - {% if status.is_setup %} - {{ block.super }} - {% endif %} - -{% endblock %} - {% block configuration %} - {% if status.is_setup %} +

{% trans "Profile" %}

-

{% trans "Profile" %}

+

+ {% blocktrans trimmed %} + To connect to {{ box_name }}'s VPN, you need to download a profile and + feed it to an OpenVPN client on your mobile or desktop machine. OpenVPN + Clients are available for most platforms. Click "Learn more..." above for + recommended clients and instructions on how to configure them. + {% endblocktrans %} +

-

- {% blocktrans trimmed %} - To connect to {{ box_name }}'s VPN, you need to download a - profile and feed it to an OpenVPN client on your mobile or - desktop machine. OpenVPN Clients are available for most - platforms. Click "Learn more..." above for recommended clients - and instructions on how to configure them. - {% endblocktrans %} -

+

+ {% blocktrans trimmed %} + Profile is specific to each user of {{ box_name }}. Keep it a secret. + {% endblocktrans %} +

-

- {% blocktrans trimmed %} - Profile is specific to each user of {{ box_name }}. Keep it a - secret. - {% endblocktrans %} -

+
+ {% csrf_token %} - - {% csrf_token %} - - -
- - {% if not using_ecc %} - {% include "migrate_to_ecc.html" %} - {% endif %} - - {% endif %} + + {% endblock %} diff --git a/plinth/modules/openvpn/tests/test_configuration.py b/plinth/modules/openvpn/tests/test_configuration.py deleted file mode 100644 index 11f8e8cee..000000000 --- a/plinth/modules/openvpn/tests/test_configuration.py +++ /dev/null @@ -1,67 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Test module for OpenVPN configuration. -""" - -import os -from unittest.mock import patch - -import pytest - -from plinth.modules import openvpn -from plinth.modules.openvpn import privileged - -pytestmark = pytest.mark.usefixtures('mock_privileged') -privileged_modules_to_mock = ['plinth.modules.openvpn.privileged'] - - -@pytest.fixture(name='keys_directory') -def fixture_keys_directory(tmp_path): - return tmp_path - - -@pytest.fixture(autouse=True) -def fixture_set_keys_directory(keys_directory): - """Set the keys directory in the actions module.""" - privileged.DH_PARAMS = f'{keys_directory}/pki/dh.pem' - privileged.EC_PARAMS_DIR = f'{keys_directory}/pki/ecparams' - - -@pytest.fixture(name='conf_file') -def fixture_conf_file(tmp_path): - """Fixture that returns an empty configuration file.""" - return str(tmp_path / 'freedombox.conf') - - -def test_identify_rsa_configuration(conf_file): - """Identify RSA configuration based on configuration file.""" - with patch('plinth.modules.openvpn.SERVER_CONFIGURATION_FILE', conf_file): - with open(conf_file, 'w', encoding='utf-8') as file_handle: - file_handle.write('dh /etc/openvpn/freedombox-keys/pki/dh.pem') - assert not openvpn.is_using_ecc() - - -def test_identify_ecc_configuration(conf_file): - """Identify ECC configuration based on configuration file.""" - with patch('plinth.modules.openvpn.SERVER_CONFIGURATION_FILE', conf_file): - with open(conf_file, 'w', encoding='utf-8') as file_handle: - file_handle.write('dh none') - assert openvpn.is_using_ecc() - - -def test_is_setup_with_rsa(keys_directory): - """is_setup should work with RSA configuration.""" - (keys_directory / 'pki').mkdir() - dh_params_file = keys_directory / 'pki' / 'dh.pem' - dh_params_file.write_text('some content') - assert privileged.is_setup() - os.remove(dh_params_file) - - -def test_is_setup_with_ecc(keys_directory): - """is_setup should work with RSA configuration.""" - (keys_directory / 'pki' / 'ecparams').mkdir(parents=True) - ec_params_file = keys_directory / 'pki' / 'ecparams' / 'somecurve.pem' - ec_params_file.write_text('some content') - assert privileged.is_setup() - os.remove(ec_params_file) diff --git a/plinth/modules/openvpn/urls.py b/plinth/modules/openvpn/urls.py index 77b24d3e1..e9382644b 100644 --- a/plinth/modules/openvpn/urls.py +++ b/plinth/modules/openvpn/urls.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -URLs for the OpenVPN module. -""" +"""URLs for the OpenVPN module.""" from django.urls import re_path @@ -11,8 +9,6 @@ from . import views urlpatterns = [ re_path(r'^apps/openvpn/$', views.OpenVPNAppView.as_view(), name='index'), - re_path(r'^apps/openvpn/setup/$', views.setup, name='setup'), - re_path(r'^apps/openvpn/ecc/$', views.ecc, name='ecc'), re_path(r'^apps/openvpn/profile/$', user_group_view(views.profile, 'vpn'), name='profile'), ] diff --git a/plinth/modules/openvpn/views.py b/plinth/modules/openvpn/views.py index f64ff29c1..3dad16fc2 100644 --- a/plinth/modules/openvpn/views.py +++ b/plinth/modules/openvpn/views.py @@ -4,11 +4,8 @@ import logging from django.http import HttpResponse -from django.shortcuts import redirect -from django.views.decorators.http import require_POST -from plinth import app as app_module -from plinth.modules import config, openvpn +from plinth.modules import config from plinth.views import AppView from . import privileged @@ -22,26 +19,6 @@ class OpenVPNAppView(AppView): app_id = 'openvpn' template_name = 'openvpn.html' - def get_context_data(self, *args, **kwargs): - """Add additional context data for template.""" - context = super().get_context_data(*args, **kwargs) - context['status'] = { - 'is_setup': privileged.is_setup(), - } - context['using_ecc'] = openvpn.is_using_ecc() - return context - - -@require_POST -def setup(_): - """Start the setup process.""" - if not privileged.is_setup(): - privileged.setup() - - app_module.App.get('openvpn').enable() - - return redirect('openvpn:index') - def profile(request): """Provide the user's profile for download.""" @@ -58,12 +35,3 @@ def profile(request): 'attachment; filename={username}.ovpn'.format(username=username) return response - - -@require_POST -def ecc(_): - """Migrate from RSA to ECC.""" - if privileged.is_setup(): - privileged.setup() - - return redirect('openvpn:index') From e8ea6fff179102d7aaf824bed0ce637e186c8e11 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 15:51:25 -0700 Subject: [PATCH 44/90] pagekite: Use privileged decorator for actions Tests: - Functional tests work - Initial setup succeeds - Configuration can be set and new configuration is properly reflected in app page and configuration files. - A new service can be added and reflects in configuration files. - Service can be deleted and reflects in configuration files. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/pagekite/__init__.py | 5 +- plinth/modules/pagekite/forms.py | 31 ++--- .../modules/pagekite/privileged.py | 125 ++++++------------ plinth/modules/pagekite/utils.py | 33 +---- plinth/modules/pagekite/views.py | 4 +- 5 files changed, 66 insertions(+), 132 deletions(-) rename actions/pagekite => plinth/modules/pagekite/privileged.py (67%) mode change 100755 => 100644 diff --git a/plinth/modules/pagekite/__init__.py b/plinth/modules/pagekite/__init__.py index d959a0286..e85189b70 100644 --- a/plinth/modules/pagekite/__init__.py +++ b/plinth/modules/pagekite/__init__.py @@ -1,11 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure PageKite. -""" +"""FreedomBox app to configure PageKite.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import Daemon diff --git a/plinth/modules/pagekite/forms.py b/plinth/modules/pagekite/forms.py index a05c8a6b8..0ca0539a1 100644 --- a/plinth/modules/pagekite/forms.py +++ b/plinth/modules/pagekite/forms.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later +"""Forms for configuring Pagekite.""" import copy -import json from django import forms from django.contrib import messages @@ -9,16 +9,14 @@ from django.core import validators from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy -from plinth.errors import ActionError - -from . import utils +from . import privileged, utils class TrimmedCharField(forms.CharField): - """Trim the contents of a CharField""" + """Trim the contents of a CharField.""" def clean(self, value): - """Clean and validate the field value""" + """Clean and validate the field value.""" if value: value = value.strip() @@ -26,7 +24,7 @@ class TrimmedCharField(forms.CharField): class ConfigurationForm(forms.Form): - """Configure PageKite credentials and frontend""" + """Configure PageKite credentials and frontend.""" server_domain = forms.CharField( label=gettext_lazy('Server domain'), required=False, @@ -72,9 +70,7 @@ class ConfigurationForm(forms.Form): if old != new: frontend = f"{new['server_domain']}:{new['server_port']}" - utils.run([ - 'set-config', '--kite-name', kite_name, '--frontend', frontend - ], input=new['kite_secret'].encode()) + privileged.set_config(frontend, kite_name, new['kite_secret']) messages.success(request, _('Configuration updated')) # Update kite name registered with Name Services module. @@ -82,7 +78,8 @@ class ConfigurationForm(forms.Form): class BaseCustomServiceForm(forms.Form): - """Basic form functionality to handle a custom service""" + """Basic form functionality to handle a custom service.""" + choices = [('http', 'http'), ('https', 'https'), ('raw', 'raw')] protocol = forms.ChoiceField(choices=choices, label=gettext_lazy('protocol')) @@ -96,7 +93,7 @@ class BaseCustomServiceForm(forms.Form): required=False) def convert_formdata_to_service(self, formdata): - """Add information to make a service out of the form data""" + """Add information to make a service out of the form data.""" # convert integers to str (to compare values with DEFAULT_SERVICES) for field in ('frontend_port', 'backend_port'): formdata[field] = str(formdata[field]) @@ -126,15 +123,15 @@ class DeleteCustomServiceForm(BaseCustomServiceForm): def delete(self, request): service = self.convert_formdata_to_service(self.cleaned_data) - utils.run(['remove-service', '--service', json.dumps(service)]) + privileged.remove_service(service) messages.success(request, _('Deleted custom service')) class AddCustomServiceForm(BaseCustomServiceForm): - """Adds the save() method and validation to not add predefined services""" + """Adds the save() method and validation to not add predefined services.""" def matches_predefined_service(self, formdata): - """Returns whether the user input matches a predefined service""" + """Return whether the user input matches a predefined service.""" service = self.convert_formdata_to_service(formdata) match_found = False for predefined_service_obj in utils.PREDEFINED_SERVICES.values(): @@ -168,9 +165,9 @@ class AddCustomServiceForm(BaseCustomServiceForm): def save(self, request): service = self.convert_formdata_to_service(self.cleaned_data) try: - utils.run(['add-service', '--service', json.dumps(service)]) + privileged.add_service(service) messages.success(request, _('Added custom service')) - except ActionError as exception: + except Exception as exception: if "already exists" in str(exception): messages.error(request, _('This service already exists')) else: diff --git a/actions/pagekite b/plinth/modules/pagekite/privileged.py old mode 100755 new mode 100644 similarity index 67% rename from actions/pagekite rename to plinth/modules/pagekite/privileged.py index b57ad2cd1..f9b5eec69 --- a/actions/pagekite +++ b/plinth/modules/pagekite/privileged.py @@ -1,21 +1,15 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for PageKite interface. -""" +"""Configure PageKite.""" -import argparse -import json import os -import sys +from typing import Union import augeas from plinth import action_utils +from plinth.actions import privileged from plinth.modules.pagekite import utils -aug = None - PATHS = { 'service_on': os.path.join(utils.CONF_PATH, '*', 'service_on', '*'), @@ -32,35 +26,10 @@ PATHS = { } -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - # Configuration - subparsers.add_parser('get-config', help='Return current configuration') - set_config = subparsers.add_parser( - 'set-config', - help='Configure kite name, its secret and frontend. Secret is read ' - 'from stdin.') - set_config.add_argument('--kite-name', - help='Name of the kite (eg: mybox.pagekite.me)') - set_config.add_argument('--frontend', help='Frontend url') - - # Add/remove pagekite services (service_on entries) - add_service = subparsers.add_parser('add-service', - help='Add a pagekite service') - add_service.add_argument('--service', help='json service dictionary') - remove_service = subparsers.add_parser('remove-service', - help='Remove a pagekite service') - remove_service.add_argument('--service', help='json service dictionary') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_get_config(_): - """Print the current configuration as JSON dictionary.""" +@privileged +def get_config() -> dict[str, object]: + """Return the current configuration as JSON dictionary.""" + aug = _augeas_load() if aug.match(PATHS['abort_not_configured']): aug.remove(PATHS['abort_not_configured']) aug.save() @@ -70,9 +39,9 @@ def subcommand_get_config(_): else: frontend = aug.get(PATHS['frontend']) or '' - frontend = frontend.split(':') - server_domain = frontend[0] - server_port = frontend[1] if len(frontend) >= 2 else '80' + frontend_parts = frontend.split(':') + server_domain = frontend_parts[0] + server_port = frontend_parts[1] if len(frontend_parts) >= 2 else '80' status = { 'kite_name': aug.get(PATHS['kitename']), @@ -113,30 +82,32 @@ def subcommand_get_config(_): service['url'] = url - print(json.dumps(status)) + return status -def subcommand_set_config(arguments): +@privileged +def set_config(frontend: str, kite_name: str, kite_secret: str): """Set pagekite kite name, secret and frontend URL.""" + aug = _augeas_load() aug.remove(PATHS['abort_not_configured']) - aug.set(PATHS['kitename'], arguments.kite_name) - aug.set(PATHS['kitesecret'], sys.stdin.read()) + aug.set(PATHS['kitename'], kite_name) + aug.set(PATHS['kitesecret'], kite_secret) - frontend_domain = arguments.frontend.split(':')[0] + frontend_domain = frontend.split(':')[0] if frontend_domain in ('pagekite.net', 'defaults', 'default'): aug.set(PATHS['defaults'], '') aug.remove(PATHS['frontend']) else: aug.remove(PATHS['defaults']) - aug.set(PATHS['frontend'], arguments.frontend) + aug.set(PATHS['frontend'], frontend) aug.save() for service_name in utils.PREDEFINED_SERVICES.keys(): service = utils.PREDEFINED_SERVICES[service_name]['params'] try: - _add_service(service) + _add_service(aug, service) except RuntimeError: pass @@ -146,10 +117,12 @@ def subcommand_set_config(arguments): action_utils.service_restart('pagekite') -def subcommand_remove_service(arguments): - """Searches and removes the service(s) that match all given parameters""" - service = utils.load_service(arguments.service) - paths = _get_existing_service_paths(service) +@privileged +def remove_service(service: dict[str, Union[str, bool]]): + """Search and remove the service(s) that match all given parameters.""" + aug = _augeas_load() + service = utils.load_service(service) + paths = _get_existing_service_paths(aug, service) # TODO: theoretically, everything to do here is: # [aug.remove(path) for path in paths] # but augeas won't let you save the changed files and doesn't say why @@ -172,8 +145,8 @@ def subcommand_remove_service(arguments): action_utils.service_restart('pagekite') -def _get_existing_service_paths(service, keys=None): - """Return paths of existing services that match the given service params""" +def _get_existing_service_paths(aug, service, keys=None): + """Return paths of existing services that match the given service.""" # construct an augeas query path with patterns like: # */service_on/*[protocol='http'] path = PATHS['service_on'] @@ -182,13 +155,13 @@ def _get_existing_service_paths(service, keys=None): return aug.match(path) -def _add_service(service): +def _add_service(aug, service): """Add a new service into configuration.""" - if _get_existing_service_paths(service, ['protocol', 'kitename']): + if _get_existing_service_paths(aug, service, ['protocol', 'kitename']): msg = "Service with the parameters %s already exists" raise RuntimeError(msg % service) - root = _get_new_service_path(service['protocol']) + root = _get_new_service_path(aug, service['protocol']) # TODO: after adding a service, augeas fails writing the config; # so add the service_on entry manually instead path = _convert_augeas_path_to_filepath(root) @@ -197,16 +170,18 @@ def _add_service(service): servicefile.write(line) -def subcommand_add_service(arguments): - """Add one service""" - service = utils.load_service(arguments.service) - _add_service(service) +@privileged +def add_service(service: dict[str, Union[str, bool]]): + """Add one service.""" + aug = _augeas_load() + service = utils.load_service(service) + _add_service(aug, service) action_utils.service_try_restart('pagekite') def _convert_augeas_path_to_filepath(augpath, prefix='/files', suffix='service_on'): - """Convert an augeas service_on path to the actual file path""" + """Convert an augeas service_on path to the actual file path.""" if augpath.startswith(prefix): augpath = augpath.replace(prefix, "", 1) @@ -216,35 +191,21 @@ def _convert_augeas_path_to_filepath(augpath, prefix='/files', return augpath.rstrip('/') -def _get_new_service_path(protocol): - """Get the augeas path of a new service for a protocol +def _get_new_service_path(aug, protocol): + """Get the augeas path of a new service for a protocol. - This takes care of existing services using a /service_on/*/ query""" + This takes care of existing services using a /service_on/*/ query + """ root = utils.get_augeas_servicefile_path(protocol) new_index = len(aug.match(root + '/*')) + 1 return os.path.join(root, str(new_index)) -def augeas_load(): +def _augeas_load(): """Initialize Augeas.""" - global aug aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) aug.set('/augeas/load/Pagekite/lens', 'Pagekite.lns') aug.set('/augeas/load/Pagekite/incl[last() + 1]', '/etc/pagekite.d/*.rc') aug.load() - - -def main(): - """Parse arguments and perform all duties""" - augeas_load() - - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == "__main__": - main() + return aug diff --git a/plinth/modules/pagekite/utils.py b/plinth/modules/pagekite/utils.py index 8b00cf7b6..77d5058e1 100644 --- a/plinth/modules/pagekite/utils.py +++ b/plinth/modules/pagekite/utils.py @@ -1,12 +1,11 @@ # SPDX-License-Identifier: AGPL-3.0-or-later +"""Utilities for configuring Pagekite.""" -import json import logging import os from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth.signals import domain_added, domain_removed @@ -80,21 +79,6 @@ PREDEFINED_SERVICES = { } -def get_config(): - """Return the current PageKite configuration.""" - return json.loads(run(['get-config'])) - - -def run(arguments, superuser=True, input=None): - """Run a given command and raise exception if there was an error""" - command = 'pagekite' - - if superuser: - return actions.superuser_run(command, arguments, input=input) - else: - return actions.run(command, arguments, input=input) - - def convert_service_to_string(service): """ Convert service dict into a ":"-separated parameter string @@ -110,15 +94,14 @@ def convert_service_to_string(service): return service_string -def load_service(json_service): - """ create a service out of json command-line argument +def load_service(service): + """Create a service out of json command-line argument. 1) parse json 2) only use the parameters that we need (SERVICE_PARAMS) 3) convert unicode to strings """ - service = json.loads(json_service) - return dict((str(key), str(service[key])) for key in SERVICE_PARAMS) + return {str(key): str(service[key]) for key in SERVICE_PARAMS} def get_augeas_servicefile_path(protocol): @@ -176,7 +159,8 @@ def update_names_module(is_enabled=None): if is_enabled is None and not app_module.App.get('pagekite').is_enabled(): return - config = get_config() + from . import privileged + config = privileged.get_config() enabled_services = [ service for service, value in config['predefined_services'].items() if value @@ -186,8 +170,3 @@ def update_names_module(is_enabled=None): domain_type='domain-type-pagekite', name=config['kite_name'], services=enabled_services) - - -if __name__ == "__main__": - import doctest - doctest.testmod() diff --git a/plinth/modules/pagekite/views.py b/plinth/modules/pagekite/views.py index b5307b9cd..c5dde2e59 100644 --- a/plinth/modules/pagekite/views.py +++ b/plinth/modules/pagekite/views.py @@ -8,7 +8,7 @@ from django.views.generic.edit import FormView from plinth.views import AppView -from . import utils +from . import privileged from .forms import (AddCustomServiceForm, ConfigurationForm, DeleteCustomServiceForm) @@ -50,7 +50,7 @@ class ConfigurationView(AppView): def __init__(self, *args, **kwargs): """Load and store the current configuration.""" super().__init__(*args, **kwargs) - self.config = utils.get_config() + self.config = privileged.get_config() self.initial = self.config def get_context_data(self, *args, **kwargs): From 7870d43c33278ad74fdebf1704af0b99c07d274b Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 15:54:43 -0700 Subject: [PATCH 45/90] power: Use privileged decorator for actions Tests: - Reboot works, the process works in the background showing apps page - Shutdown works, the process works in the background showing apps page Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/power | 43 ------------------------------ plinth/modules/power/privileged.py | 18 +++++++++++++ plinth/modules/power/views.py | 11 ++++---- 3 files changed, 23 insertions(+), 49 deletions(-) delete mode 100755 actions/power create mode 100644 plinth/modules/power/privileged.py diff --git a/actions/power b/actions/power deleted file mode 100755 index 4411cf992..000000000 --- a/actions/power +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for power controls. -""" - -import argparse -import subprocess - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('restart', help='Restart the system') - subparsers.add_parser('shutdown', help='Shut down the system') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_restart(_): - """Restart the system.""" - subprocess.call('reboot') - - -def subcommand_shutdown(_): - """Shut down the system.""" - subprocess.call(['shutdown', 'now']) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/power/privileged.py b/plinth/modules/power/privileged.py new file mode 100644 index 000000000..06e22967c --- /dev/null +++ b/plinth/modules/power/privileged.py @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Shutdown/restart the system.""" + +import subprocess + +from plinth.actions import privileged + + +@privileged +def restart(): + """Restart the system.""" + subprocess.call('reboot') + + +@privileged +def shutdown(): + """Shut down the system.""" + subprocess.call(['shutdown', 'now']) diff --git a/plinth/modules/power/views.py b/plinth/modules/power/views.py index d88d10eea..2a53b8a95 100644 --- a/plinth/modules/power/views.py +++ b/plinth/modules/power/views.py @@ -1,18 +1,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for power module. -""" +"""FreedomBox app for power controls.""" from django.forms import Form from django.shortcuts import redirect from django.template.response import TemplateResponse from django.urls import reverse -from plinth import actions from plinth import app as app_module from plinth import package from plinth.views import AppView +from . import privileged + class PowerAppView(AppView): """Show power app main page.""" @@ -32,7 +31,7 @@ def restart(request): form = None if request.method == 'POST': - actions.superuser_run('power', ['restart'], run_in_background=True) + privileged.restart(_run_in_background=True) return redirect(reverse('apps')) app = app_module.App.get('power') @@ -51,7 +50,7 @@ def shutdown(request): form = None if request.method == 'POST': - actions.superuser_run('power', ['shutdown'], run_in_background=True) + privileged.shutdown(_run_in_background=True) return redirect(reverse('apps')) app = app_module.App.get('power') From 8478450467c1321bac7a022594f648df315cb581 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 15:57:37 -0700 Subject: [PATCH 46/90] quassel: Use privileged decorator for actions Tests: - Functional tests work - Setting the domain updates the configuration file, reflects in the app page Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/quassel | 40 ---------------------------- plinth/modules/quassel/__init__.py | 9 +++---- plinth/modules/quassel/privileged.py | 13 +++++++++ 3 files changed, 16 insertions(+), 46 deletions(-) delete mode 100755 actions/quassel create mode 100644 plinth/modules/quassel/privileged.py diff --git a/actions/quassel b/actions/quassel deleted file mode 100755 index c22e14c5e..000000000 --- a/actions/quassel +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Quassel. -""" - -import argparse -import pathlib - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparser = subparsers.add_parser('set-domain', - help='Setup Quassel configuration') - subparser.add_argument('domain_name', help='Domain name to be allowed') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_set_domain(arguments): - """Write a file containing domain name.""" - domain_file = pathlib.Path('/var/lib/quassel/domain-freedombox') - domain_file.write_text(arguments.domain_name, encoding='utf-8') - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/quassel/__init__.py b/plinth/modules/quassel/__init__.py index 0405e9cb9..284e67642 100644 --- a/plinth/modules/quassel/__init__.py +++ b/plinth/modules/quassel/__init__.py @@ -1,14 +1,11 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for Quassel. -""" +"""FreedomBox app for Quassel.""" import pathlib from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -20,7 +17,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ format_lazy( @@ -108,7 +105,7 @@ class QuasselApp(app_module.App): def set_domain(domain): """Set the TLS domain by writing a file to data directory.""" if domain: - actions.superuser_run('quassel', ['set-domain', domain]) + privileged.set_domain(domain) def get_domain(): diff --git a/plinth/modules/quassel/privileged.py b/plinth/modules/quassel/privileged.py new file mode 100644 index 000000000..bab66e9dd --- /dev/null +++ b/plinth/modules/quassel/privileged.py @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure Quassel.""" + +import pathlib + +from plinth.actions import privileged + + +@privileged +def set_domain(domain_name: str): + """Write a file containing domain name.""" + domain_file = pathlib.Path('/var/lib/quassel/domain-freedombox') + domain_file.write_text(domain_name, encoding='utf-8') From 89a4d259099fcd7fe4663c02ec4718eefea455b6 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 25 Aug 2022 16:31:57 -0700 Subject: [PATCH 47/90] radicale: Use privileged decorator for actions Tests: - Functional tests work - When the app is enabled, if the log path does not exist, it is created /var/log/radicale. - Not tested: upgrading from older version to 3.x - Setting the access rights works. It is reflected in the app page and configuration file /etc/radicale/config. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/radicale | 76 --------------------------- plinth/modules/radicale/__init__.py | 8 ++- plinth/modules/radicale/privileged.py | 47 +++++++++++++++++ plinth/modules/radicale/views.py | 7 +-- 4 files changed, 52 insertions(+), 86 deletions(-) delete mode 100755 actions/radicale create mode 100644 plinth/modules/radicale/privileged.py diff --git a/actions/radicale b/actions/radicale deleted file mode 100755 index 4c745e5d8..000000000 --- a/actions/radicale +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Radicale. -""" - -import argparse -import os - -import augeas - -from plinth import action_utils - -CONFIG_FILE = '/etc/radicale/config' -LOG_PATH = '/var/log/radicale' - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - configure = subparsers.add_parser('configure', - help='Configure various options') - configure.add_argument('--rights_type', - help='Set the rights type for radicale') - subparsers.add_parser('fix-paths', help='Ensure paths exists') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_configure(arguments): - """Sets the radicale rights type to a particular value""" - if arguments.rights_type == 'owner_only': - # Default rights file is equivalent to owner_only. - arguments.rights_type = 'from_file' - - aug = load_augeas() - aug.set('/files' + CONFIG_FILE + '/rights/type', arguments.rights_type) - aug.save() - - action_utils.service_try_restart('uwsgi') - - -def subcommand_fix_paths(_): - """Fix log path to work around a bug.""" - # Workaround for bug in radicale's uwsgi script (#931201) - if not os.path.exists(LOG_PATH): - os.makedirs(LOG_PATH) - - -def load_augeas(): - """Initialize Augeas.""" - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - - # INI file lens - aug.set('/augeas/load/Puppet/lens', 'Puppet.lns') - aug.set('/augeas/load/Puppet/incl[last() + 1]', CONFIG_FILE) - - aug.load() - return aug - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/radicale/__init__.py b/plinth/modules/radicale/__init__.py index 118f60164..372addf5c 100644 --- a/plinth/modules/radicale/__init__.py +++ b/plinth/modules/radicale/__init__.py @@ -8,7 +8,6 @@ import logging import augeas from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.modules.apache.components import Uwsgi, Webserver @@ -18,7 +17,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages, install from plinth.utils import Version, format_lazy -from . import manifest +from . import manifest, privileged _description = [ format_lazy( @@ -93,7 +92,7 @@ class RadicaleApp(app_module.App): def enable(self): """Fix missing directories before enabling radicale.""" - actions.superuser_run('radicale', ['fix-paths']) + privileged.fix_paths() super().enable() def setup(self, old_version): @@ -113,8 +112,7 @@ class RadicaleApp(app_module.App): rights = get_rights_value() install(['radicale'], force_configuration='new') - actions.superuser_run('radicale', - ['configure', '--rights_type', rights]) + privileged.configure(rights) return True diff --git a/plinth/modules/radicale/privileged.py b/plinth/modules/radicale/privileged.py new file mode 100644 index 000000000..7c950dcf0 --- /dev/null +++ b/plinth/modules/radicale/privileged.py @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure Radicale.""" + +import os + +import augeas + +from plinth import action_utils +from plinth.actions import privileged + +CONFIG_FILE = '/etc/radicale/config' +LOG_PATH = '/var/log/radicale' + + +@privileged +def configure(rights_type: str): + """Set the radicale rights type to a particular value.""" + if rights_type == 'owner_only': + # Default rights file is equivalent to owner_only. + rights_type = 'from_file' + + aug = load_augeas() + aug.set('/files' + CONFIG_FILE + '/rights/type', rights_type) + aug.save() + + action_utils.service_try_restart('uwsgi') + + +@privileged +def fix_paths(): + """Fix log path to work around a bug.""" + # Workaround for bug in radicale's uwsgi script (#931201) + if not os.path.exists(LOG_PATH): + os.makedirs(LOG_PATH) + + +def load_augeas(): + """Initialize Augeas.""" + aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + + augeas.Augeas.NO_MODL_AUTOLOAD) + + # INI file lens + aug.set('/augeas/load/Puppet/lens', 'Puppet.lns') + aug.set('/augeas/load/Puppet/incl[last() + 1]', CONFIG_FILE) + + aug.load() + return aug diff --git a/plinth/modules/radicale/views.py b/plinth/modules/radicale/views.py index 88d56cac6..e7d73b7a6 100644 --- a/plinth/modules/radicale/views.py +++ b/plinth/modules/radicale/views.py @@ -6,10 +6,9 @@ Views for radicale module. from django.contrib import messages from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth.views import AppView -from . import get_rights_value +from . import get_rights_value, privileged from .forms import RadicaleForm @@ -28,9 +27,7 @@ class RadicaleAppView(AppView): """Change the access control of Radicale service.""" data = form.cleaned_data if get_rights_value() != data['access_rights']: - actions.superuser_run( - 'radicale', - ['configure', '--rights_type', data['access_rights']]) + privileged.configure(data['access_rights']) messages.success(self.request, _('Access rights configuration updated')) return super().form_valid(form) From 8db063b59b17d67b52a05396c451bcea20590d49 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 15 Sep 2022 15:43:37 -0700 Subject: [PATCH 48/90] roundcube: Minor update to comment in privileged actions Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/roundcube/privileged.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plinth/modules/roundcube/privileged.py b/plinth/modules/roundcube/privileged.py index bfcc99fe5..1fd6591ba 100644 --- a/plinth/modules/roundcube/privileged.py +++ b/plinth/modules/roundcube/privileged.py @@ -35,7 +35,7 @@ def setup(): @privileged def get_config() -> dict[str, bool]: - """Print the current configuration as JSON.""" + """Return the current configuration as a dictionary.""" pattern = r'\s*\$config\[\s*\'([^\']*)\'\s*\]\s*=\s*\'([^\']*)\'\s*;' _config = {} try: From 52f42a4f74a11df5e68c723c248dc2d7ed019705 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 10:19:08 -0700 Subject: [PATCH 49/90] searx: Use privileged decorator for actions Tests: - Functional tests work - Initial setup works - UWSGI configuration is created and daemon is running. - Enabling and disabling public access works. Public access file is created/removed. App page shows current value. If exception is raised, error is shown properly. - Setting safe search to all three values works. Configuration file is updated properly. App page shows current value properly. If exception is raised, error is shown properly. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/searx/__init__.py | 21 ++--- plinth/modules/searx/forms.py | 5 +- .../modules/searx/privileged.py | 76 +++++-------------- plinth/modules/searx/views.py | 17 ++--- 4 files changed, 33 insertions(+), 86 deletions(-) rename actions/searx => plinth/modules/searx/privileged.py (68%) mode change 100755 => 100644 diff --git a/plinth/modules/searx/__init__.py b/plinth/modules/searx/__init__.py index 27b8fe9cb..675483d41 100644 --- a/plinth/modules/searx/__init__.py +++ b/plinth/modules/searx/__init__.py @@ -1,13 +1,10 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Searx. -""" +"""FreedomBox app to configure Searx.""" import os from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.modules.apache.components import Uwsgi, Webserver @@ -16,7 +13,7 @@ from plinth.modules.firewall.components import Firewall from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages -from . import manifest +from . import manifest, privileged _description = [ _('Searx is a privacy-respecting Internet metasearch engine. ' @@ -95,9 +92,9 @@ class SearxApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('searx', ['setup']) + privileged.setup() if not old_version or old_version < 3: - actions.superuser_run('searx', ['disable-public-access']) + privileged.disable_public_access() self.enable() self.set_shortcut_login_required(True) @@ -115,12 +112,6 @@ class SearxWebserverAuth(Webserver): super().enable() -def get_safe_search_setting(): - """Get the current value of the safe search setting for Searx.""" - value = actions.superuser_run('searx', ['get-safe-search']) - return int(value.strip()) - - def is_public_access_enabled(): """Check whether public access is enabled for Searx.""" return os.path.exists(manifest.PUBLIC_ACCESS_SETTING_FILE) @@ -128,7 +119,7 @@ def is_public_access_enabled(): def enable_public_access(): """Allow Searx app to be accessed by anyone with access.""" - actions.superuser_run('searx', ['enable-public-access']) + privileged.enable_public_access() app = app_module.App.get('searx') app.get_component('webserver-searx-auth').disable() app.set_shortcut_login_required(False) @@ -136,7 +127,7 @@ def enable_public_access(): def disable_public_access(): """Allow Searx app to be accessed by logged-in users only.""" - actions.superuser_run('searx', ['disable-public-access']) + privileged.disable_public_access() app = app_module.App.get('searx') app.get_component('webserver-searx-auth').enable() app.set_shortcut_login_required(True) diff --git a/plinth/modules/searx/forms.py b/plinth/modules/searx/forms.py index e4cddb966..11f46cce8 100644 --- a/plinth/modules/searx/forms.py +++ b/plinth/modules/searx/forms.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Django form for configuring Searx. -""" +"""Django form for configuring Searx.""" from django import forms from django.utils.translation import gettext_lazy as _ @@ -9,6 +7,7 @@ from django.utils.translation import gettext_lazy as _ class SearxForm(forms.Form): """Searx configuration form.""" + safe_search = forms.ChoiceField( label=_('Safe Search'), help_text=_( 'Select the default family filter to apply to your search results.' diff --git a/actions/searx b/plinth/modules/searx/privileged.py old mode 100755 new mode 100644 similarity index 68% rename from actions/searx rename to plinth/modules/searx/privileged.py index 6f9aca347..9279d61b3 --- a/actions/searx +++ b/plinth/modules/searx/privileged.py @@ -1,10 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for searx. -""" +"""Configure searx.""" -import argparse import gzip import os import pathlib @@ -15,6 +11,7 @@ import augeas import yaml from plinth import action_utils +from plinth.actions import privileged from plinth.modules.searx.manifest import PUBLIC_ACCESS_SETTING_FILE from plinth.utils import gunzip @@ -23,34 +20,6 @@ SETTINGS_FILE = '/etc/searx/settings.yml' UWSGI_FILE = '/etc/uwsgi/apps-available/searx.ini' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser( - 'setup', help='Perform post-installation operations for Searx') - - subparsers.add_parser('enable-public-access', - help='Enable public access to the Searx application') - subparsers.add_parser( - 'disable-public-access', - help='Disable public access to the Searx application') - - safe_search = subparsers.add_parser( - 'set-safe-search', - help='Set the default filter for safe search on Searx') - safe_search.add_argument( - 'filter', type=int, - help='Filter results. 0: None, 1: Moderate, 2: Strict') - - subparsers.add_parser('get-safe-search', - help='Print the value of the safe search setting.') - - subparsers.required = True - return parser.parse_args() - - def _copy_uwsgi_configuration(): """Copy example uwsgi configuration @@ -100,21 +69,22 @@ def _set_safe_search(settings): settings['search']['safe_search'] = 1 -def subcommand_set_safe_search(arguments): +@privileged +def set_safe_search(filter_: int): """Set safe search filter for search results.""" - value = arguments.filter settings = read_settings() - settings['search']['safe_search'] = value + settings['search']['safe_search'] = filter_ write_settings(settings) -def subcommand_get_safe_search(_): - """Print the value of the safe search setting.""" +@privileged +def get_safe_search() -> int: + """Return the value of the safe search setting.""" if os.path.exists(SETTINGS_FILE): settings = read_settings() - print(settings['search']['safe_search']) + return int(settings['search']['safe_search']) else: - print(0) + return 0 def read_settings(): @@ -138,15 +108,16 @@ def _get_example_settings_file(): def _update_search_engines(settings): - """Updates settings with the latest supported search engines.""" + """Update settings with the latest supported search engines.""" example_settings_file = _get_example_settings_file() open_func = gzip.open if example_settings_file.suffix == '.gz' else open with open_func(example_settings_file, 'rb') as example_settings: settings['engines'] = yaml.safe_load(example_settings)['engines'] -def subcommand_setup(_): - """Post installation actions for Searx""" +@privileged +def setup(): + """Post installation actions for Searx.""" _copy_uwsgi_configuration() _update_uwsgi_configuration() @@ -169,25 +140,14 @@ def subcommand_setup(_): action_utils.service_restart('uwsgi') -def subcommand_enable_public_access(_): +@privileged +def enable_public_access(): """Enable public access to the SearX application.""" open(PUBLIC_ACCESS_SETTING_FILE, 'w', encoding='utf-8').close() -def subcommand_disable_public_access(_): +@privileged +def disable_public_access(): """Disable public access to the SearX application.""" if os.path.exists(PUBLIC_ACCESS_SETTING_FILE): os.remove(PUBLIC_ACCESS_SETTING_FILE) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/searx/views.py b/plinth/modules/searx/views.py index dbe80e658..c29f33901 100644 --- a/plinth/modules/searx/views.py +++ b/plinth/modules/searx/views.py @@ -1,29 +1,27 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Django views for Searx. -""" +"""Django views for Searx.""" from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import actions from plinth import app as app_module from plinth import views -from plinth.errors import ActionError from plinth.modules import searx +from . import privileged from .forms import SearxForm class SearxAppView(views.AppView): """Serve configuration page.""" + app_id = 'searx' form_class = SearxForm def get_initial(self): """Return the status of the service to fill in the form.""" initial = super().get_initial() - initial['safe_search'] = searx.get_safe_search_setting() + initial['safe_search'] = privileged.get_safe_search() initial['public_access'] = searx.is_public_access_enabled() and \ app_module.App.get('searx').is_enabled() return initial @@ -35,10 +33,9 @@ class SearxAppView(views.AppView): if str(old_data['safe_search']) != form_data['safe_search']: try: - actions.superuser_run( - 'searx', ['set-safe-search', form_data['safe_search']]) + privileged.set_safe_search(int(form_data['safe_search'])) messages.success(self.request, _('Configuration updated.')) - except ActionError: + except Exception: messages.error(self.request, _('An error occurred during configuration.')) @@ -49,7 +46,7 @@ class SearxAppView(views.AppView): else: searx.disable_public_access() messages.success(self.request, _('Configuration updated.')) - except ActionError: + except Exception: messages.error(self.request, _('An error occurred during configuration.')) From 1e30b4c8fc4379f4070487ed821fdcb1d3c215c0 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 29 Sep 2022 17:11:10 -0700 Subject: [PATCH 50/90] searx: Show status of public access irrespective of enabled state - When the app is disabled, configuration can still be updated. Attempts to enable the setting while app is disabled seemingly fail. Tests: - Functional tests pass. - When public access is enabled and app is disabled, the page still shows public access as enabled. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/upgrades | 5 +++-- plinth/modules/searx/views.py | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/actions/upgrades b/actions/upgrades index 66acce5dc..3365f991b 100755 --- a/actions/upgrades +++ b/actions/upgrades @@ -480,8 +480,9 @@ def _update_searx(reenable=False): Re-enable if previously enabled.""" if pathlib.Path('/etc/searx/settings.yml').exists(): print('Updating searx search engines list...', flush=True) - subprocess.run(['/usr/share/plinth/actions/searx', 'setup'], - check=True) + subprocess.run([ + '/usr/share/plinth/actions/actions', 'searx', 'setup', '--no-args' + ], check=True) if reenable: print('Re-enabling searx after upgrade...', flush=True) subprocess.run([ diff --git a/plinth/modules/searx/views.py b/plinth/modules/searx/views.py index c29f33901..f71e3a641 100644 --- a/plinth/modules/searx/views.py +++ b/plinth/modules/searx/views.py @@ -4,7 +4,6 @@ from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import app as app_module from plinth import views from plinth.modules import searx @@ -22,8 +21,7 @@ class SearxAppView(views.AppView): """Return the status of the service to fill in the form.""" initial = super().get_initial() initial['safe_search'] = privileged.get_safe_search() - initial['public_access'] = searx.is_public_access_enabled() and \ - app_module.App.get('searx').is_enabled() + initial['public_access'] = searx.is_public_access_enabled() return initial def form_valid(self, form): From 97706cef8ed80bfa0117cee2f57ec7e090840491 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 10:23:47 -0700 Subject: [PATCH 51/90] security: Use privileged decorator for actions Tests: - Functional tests work - Initial setup during first setup works - Restricted access is enabled - Enabling/disabling restricted access works. Configuration file is updated and app page shows correct value. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/security | 67 --------------------------- plinth/modules/security/__init__.py | 41 ++++------------ plinth/modules/security/privileged.py | 56 ++++++++++++++++++++++ plinth/modules/security/views.py | 13 +++--- 4 files changed, 71 insertions(+), 106 deletions(-) delete mode 100755 actions/security create mode 100644 plinth/modules/security/privileged.py diff --git a/actions/security b/actions/security deleted file mode 100755 index f61775dcb..000000000 --- a/actions/security +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Helper for security configuration -""" - -import argparse -import os - -from plinth.modules.security import (ACCESS_CONF_FILE, ACCESS_CONF_FILE_OLD, - ACCESS_CONF_SNIPPET, ACCESS_CONF_SNIPPETS) - - -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser( - 'enable-restricted-access', - help='Restrict console login to users in admin or sudo group') - subparsers.add_parser( - 'disable-restricted-access', - help='Don\'t restrict console login to users in admin or sudo group') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_enable_restricted_access(_): - """Restrict console login to users in admin or sudo group.""" - try: - os.mkdir(os.path.dirname(ACCESS_CONF_FILE)) - except FileExistsError: - pass - - with open(ACCESS_CONF_FILE, 'w', encoding='utf-8') as conffile: - conffile.write(ACCESS_CONF_SNIPPET + '\n') - - -def subcommand_disable_restricted_access(_): - """Don't restrict console login to users in admin or sudo group.""" - with open(ACCESS_CONF_FILE_OLD, 'r', encoding='utf-8') as conffile: - lines = conffile.readlines() - - with open(ACCESS_CONF_FILE_OLD, 'w', encoding='utf-8') as conffile: - for line in lines: - if line.strip() not in ACCESS_CONF_SNIPPETS: - conffile.write(line) - - try: - os.remove(ACCESS_CONF_FILE) - except OSError: - pass - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/security/__init__.py b/plinth/modules/security/__init__.py index 8f46d2990..d43a0bf00 100644 --- a/plinth/modules/security/__init__.py +++ b/plinth/modules/security/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for security configuration. -""" +"""FreedomBox app for security configuration.""" import re import subprocess @@ -16,13 +14,7 @@ from plinth.daemon import Daemon, RelatedDaemon from plinth.modules.backups.components import BackupRestore from plinth.package import Packages -from . import manifest - -ACCESS_CONF_FILE = '/etc/security/access.d/50freedombox.conf' -ACCESS_CONF_FILE_OLD = '/etc/security/access.conf' -ACCESS_CONF_SNIPPET = '-:ALL EXCEPT root fbx plinth (admin) (sudo):ALL' -OLD_ACCESS_CONF_SNIPPET = '-:ALL EXCEPT root fbx (admin) (sudo):ALL' -ACCESS_CONF_SNIPPETS = [OLD_ACCESS_CONF_SNIPPET, ACCESS_CONF_SNIPPET] +from . import manifest, privileged class SecurityApp(app_module.App): @@ -66,43 +58,28 @@ class SecurityApp(app_module.App): actions.superuser_run('service', ['reload', 'fail2ban']) # Migrate to new config file. - enabled = get_restricted_access_enabled() + enabled = privileged.get_restricted_access_enabled() set_restricted_access(False) if enabled: set_restricted_access(True) def enable_fail2ban(): + """Unmask, enable and run the fail2ban service.""" actions.superuser_run('service', ['unmask', 'fail2ban']) actions.superuser_run('service', ['enable', 'fail2ban']) -def get_restricted_access_enabled(): - """Return whether restricted access is enabled""" - with open(ACCESS_CONF_FILE_OLD, 'r', encoding='utf-8') as conffile: - if any(line.strip() in ACCESS_CONF_SNIPPETS - for line in conffile.readlines()): - return True - - try: - with open(ACCESS_CONF_FILE, 'r', encoding='utf-8') as conffile: - return any(line.strip() in ACCESS_CONF_SNIPPETS - for line in conffile.readlines()) - except FileNotFoundError: - return False - - def set_restricted_access(enabled): - """Enable or disable restricted access""" - action = 'disable-restricted-access' + """Enable or disable restricted access.""" if enabled: - action = 'enable-restricted-access' - - actions.superuser_run('security', [action]) + privileged.enable_restricted_access() + else: + privileged.disable_restricted_access() def get_apps_report(): - """Return a security report for each app""" + """Return a security report for each app.""" lines = subprocess.check_output(['debsecan']).decode().split('\n') cves = defaultdict(set) for line in lines: diff --git a/plinth/modules/security/privileged.py b/plinth/modules/security/privileged.py new file mode 100644 index 000000000..b59a8f6fb --- /dev/null +++ b/plinth/modules/security/privileged.py @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Helper for security configuration.""" + +import os + +from plinth.actions import privileged + +ACCESS_CONF_FILE = '/etc/security/access.d/50freedombox.conf' +ACCESS_CONF_FILE_OLD = '/etc/security/access.conf' +ACCESS_CONF_SNIPPET = '-:ALL EXCEPT root fbx plinth (admin) (sudo):ALL' +OLD_ACCESS_CONF_SNIPPET = '-:ALL EXCEPT root fbx (admin) (sudo):ALL' +ACCESS_CONF_SNIPPETS = [OLD_ACCESS_CONF_SNIPPET, ACCESS_CONF_SNIPPET] + + +@privileged +def enable_restricted_access(): + """Restrict console login to users in admin or sudo group.""" + try: + os.mkdir(os.path.dirname(ACCESS_CONF_FILE)) + except FileExistsError: + pass + + with open(ACCESS_CONF_FILE, 'w', encoding='utf-8') as conffile: + conffile.write(ACCESS_CONF_SNIPPET + '\n') + + +@privileged +def disable_restricted_access(): + """Don't restrict console login to users in admin or sudo group.""" + with open(ACCESS_CONF_FILE_OLD, 'r', encoding='utf-8') as conffile: + lines = conffile.readlines() + + with open(ACCESS_CONF_FILE_OLD, 'w', encoding='utf-8') as conffile: + for line in lines: + if line.strip() not in ACCESS_CONF_SNIPPETS: + conffile.write(line) + + try: + os.remove(ACCESS_CONF_FILE) + except OSError: + pass + + +def get_restricted_access_enabled(): + """Return whether restricted access is enabled.""" + with open(ACCESS_CONF_FILE_OLD, 'r', encoding='utf-8') as conffile: + if any(line.strip() in ACCESS_CONF_SNIPPETS + for line in conffile.readlines()): + return True + + try: + with open(ACCESS_CONF_FILE, 'r', encoding='utf-8') as conffile: + return any(line.strip() in ACCESS_CONF_SNIPPETS + for line in conffile.readlines()) + except FileNotFoundError: + return False diff --git a/plinth/modules/security/views.py b/plinth/modules/security/views.py index 0831698d2..8d35c60f1 100644 --- a/plinth/modules/security/views.py +++ b/plinth/modules/security/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for security module -""" +"""Views for security module.""" from django.contrib import messages from django.template.response import TemplateResponse @@ -12,6 +10,7 @@ from plinth.modules import security from plinth.modules.upgrades import is_backports_requested from plinth.views import AppView +from . import privileged from .forms import SecurityForm @@ -42,15 +41,15 @@ class SecurityAppView(AppView): def get_status(request): - """Return the current status""" + """Return the current status.""" return { - 'restricted_access': security.get_restricted_access_enabled(), + 'restricted_access': privileged.get_restricted_access_enabled(), 'fail2ban_enabled': action_utils.service_is_enabled('fail2ban') } def _apply_changes(request, old_status, new_status): - """Apply the form changes""" + """Apply the form changes.""" if old_status['restricted_access'] != new_status['restricted_access']: try: security.set_restricted_access(new_status['restricted_access']) @@ -70,7 +69,7 @@ def _apply_changes(request, old_status, new_status): def report(request): - """Serve the security report page""" + """Serve the security report page.""" apps_report = security.get_apps_report() return TemplateResponse( request, 'security_report.html', { From 6e7b31a3cf9962412816adcdb0ac744aae5f7688 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 10:45:43 -0700 Subject: [PATCH 52/90] shadowsocks: Use privileged decorator for actions Tests: - Functional tests work - Initial setup works - Setting configuration works, correct configuration is updated in the configuration files and app shows the values correctly. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/shadowsocks/__init__.py | 9 +-- plinth/modules/shadowsocks/forms.py | 11 ++-- .../modules/shadowsocks/privileged.py | 57 +++++-------------- plinth/modules/shadowsocks/views.py | 20 +++---- 4 files changed, 28 insertions(+), 69 deletions(-) rename actions/shadowsocks => plinth/modules/shadowsocks/privileged.py (70%) mode change 100755 => 100644 diff --git a/plinth/modules/shadowsocks/__init__.py b/plinth/modules/shadowsocks/__init__.py index b91cb6e47..c0d45df36 100644 --- a/plinth/modules/shadowsocks/__init__.py +++ b/plinth/modules/shadowsocks/__init__.py @@ -1,12 +1,9 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Shadowsocks. -""" +"""FreedomBox app to configure Shadowsocks.""" from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -15,7 +12,7 @@ from plinth.modules.firewall.components import Firewall from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to ' @@ -85,5 +82,5 @@ class ShadowsocksApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('shadowsocks', ['setup']) + privileged.setup() self.enable() diff --git a/plinth/modules/shadowsocks/forms.py b/plinth/modules/shadowsocks/forms.py index 188e4caf5..102b77baf 100644 --- a/plinth/modules/shadowsocks/forms.py +++ b/plinth/modules/shadowsocks/forms.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring Shadowsocks. -""" +"""FreedomBox app for configuring Shadowsocks.""" from django import forms from django.utils.translation import gettext_lazy as _ @@ -22,10 +20,10 @@ METHODS = [('chacha20-ietf-poly1305', class TrimmedCharField(forms.CharField): - """Trim the contents of a CharField""" + """Trim the contents of a CharField.""" def clean(self, value): - """Clean and validate the field value""" + """Clean and validate the field value.""" if value: value = value.strip() @@ -33,7 +31,8 @@ class TrimmedCharField(forms.CharField): class ShadowsocksForm(forms.Form): - """Shadowsocks configuration form""" + """Shadowsocks configuration form.""" + server = TrimmedCharField(label=_('Server'), help_text=_('Server hostname or IP address')) diff --git a/actions/shadowsocks b/plinth/modules/shadowsocks/privileged.py old mode 100755 new mode 100644 similarity index 70% rename from actions/shadowsocks rename to plinth/modules/shadowsocks/privileged.py index 1407dadf6..39cdbe6b4 --- a/actions/shadowsocks +++ b/plinth/modules/shadowsocks/privileged.py @@ -1,42 +1,24 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Helper script for configuring Shadowsocks. -""" +"""Configure Shadowsocks.""" -import argparse import json import os import pathlib import random import string -import sys from shutil import move +from typing import Union from plinth import action_utils -from plinth.modules.shadowsocks import ShadowsocksApp +from plinth.actions import privileged SHADOWSOCKS_CONFIG_SYMLINK = '/etc/shadowsocks-libev/freedombox.json' SHADOWSOCKS_CONFIG_ACTUAL = \ '/var/lib/private/shadowsocks-libev/freedombox/freedombox.json' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Perform initial setup steps') - subparsers.add_parser('get-config', - help='Read and print JSON config to stdout') - subparsers.add_parser('merge-config', - help='Merge JSON config from stdin with existing') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_setup(_): +@privileged +def setup(): """Perform initial setup steps.""" # Only client socks5 proxy is supported for now. Disable the # server component. @@ -76,16 +58,16 @@ def subcommand_setup(_): if not wrong_state_dir.is_symlink() and wrong_state_dir.is_dir(): wrong_state_dir.rmdir() + from plinth.modules.shadowsocks import ShadowsocksApp if action_utils.service_is_enabled(ShadowsocksApp.DAEMON): action_utils.service_restart(ShadowsocksApp.DAEMON) -def subcommand_get_config(_): +@privileged +def get_config() -> dict[str, Union[int, str]]: """Read and print Shadowsocks configuration.""" - try: - print(open(SHADOWSOCKS_CONFIG_SYMLINK, 'r', encoding='utf-8').read()) - except Exception: - sys.exit(1) + config = open(SHADOWSOCKS_CONFIG_SYMLINK, 'r', encoding='utf-8').read() + return json.loads(config) def _merge_config(config): @@ -103,26 +85,13 @@ def _merge_config(config): open(SHADOWSOCKS_CONFIG_SYMLINK, 'w', encoding='utf-8').write(new_config) -def subcommand_merge_config(_): +@privileged +def merge_config(config: dict[str, Union[int, str]]): """Configure Shadowsocks.""" - config = sys.stdin.read() - config = json.loads(config) _merge_config(config) # Don't try_restart because initial configuration may not be valid so # shadowsocks will not be running even when enabled. + from . import ShadowsocksApp if action_utils.service_is_enabled(ShadowsocksApp.DAEMON): action_utils.service_restart(ShadowsocksApp.DAEMON) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/shadowsocks/views.py b/plinth/modules/shadowsocks/views.py index b1d8b74fd..ad2deda1b 100644 --- a/plinth/modules/shadowsocks/views.py +++ b/plinth/modules/shadowsocks/views.py @@ -1,21 +1,18 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring Shadowsocks. -""" - -import json +"""FreedomBox app for configuring Shadowsocks.""" from django.contrib import messages from django.utils.translation import gettext_lazy as _ -from plinth import actions, views -from plinth.errors import ActionError +from plinth import views +from . import privileged from .forms import ShadowsocksForm class ShadowsocksAppView(views.AppView): """Configuration view for Shadowsocks local socks5 proxy.""" + app_id = 'shadowsocks' form_class = ShadowsocksForm @@ -23,10 +20,8 @@ class ShadowsocksAppView(views.AppView): """Get initial values for form.""" status = super().get_initial() try: - configuration = actions.superuser_run('shadowsocks', - ['get-config']) - status.update(json.loads(configuration)) - except ActionError: + status.update(privileged.get_config()) + except Exception: status.update({ 'server': '', 'server_port': 8388, @@ -54,8 +49,7 @@ class ShadowsocksAppView(views.AppView): 'method': new_status['method'], } - actions.superuser_run('shadowsocks', ['merge-config'], - input=json.dumps(new_config).encode()) + privileged.merge_config(new_config) messages.success(self.request, _('Configuration updated')) return super().form_valid(form) From 637e6b119841d995a232f84c8a97eb17075e7a8a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 11:02:10 -0700 Subject: [PATCH 53/90] sharing: Use privileged decorator for actions Tests: - Initial setup works. - Empty Apache configuration file is created - Adding a share works all the information added is shown during editing. Configuration file is updated as expected. - List of shares is shown as expected. - When editing a share, information about share is shown correctly. Editing works are expected. - Removing a share works. - Trying to add share with a name that already exists throws a proper error message. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/sharing | 208 --------------------------- plinth/modules/sharing/__init__.py | 26 +--- plinth/modules/sharing/forms.py | 9 +- plinth/modules/sharing/privileged.py | 159 ++++++++++++++++++++ plinth/modules/sharing/views.py | 21 +-- 5 files changed, 175 insertions(+), 248 deletions(-) delete mode 100755 actions/sharing diff --git a/actions/sharing b/actions/sharing deleted file mode 100755 index 1cfeb35f1..000000000 --- a/actions/sharing +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for the sharing app. -""" - -import argparse -import json -import os -import pathlib -import re - -import augeas - -from plinth import action_utils - -APACHE_CONFIGURATION = '/etc/apache2/conf-available/sharing-freedombox.conf' - - -def parse_arguments(): - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('list', help='List all existing shares') - - add_parser = subparsers.add_parser('add', help='Add a new share') - add_parser.add_argument('--name', required=True, help='Name of the share') - add_parser.add_argument('--path', required=True, help='Disk path to share') - add_parser.add_argument('--groups', nargs='*', - help='List of groups that can access the share') - add_parser.add_argument('--is-public', required=False, default=False, - action="store_true", - help='Allow public access to this share') - - remove_parser = subparsers.add_parser('remove', - help='Remove an existing share') - remove_parser.add_argument('--name', required=True, - help='Name of the share to remove') - - subparsers.required = True - return parser.parse_args() - - -def load_augeas(): - """Initialize augeas for this app's configuration file.""" - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') - aug.set('/augeas/load/Httpd/incl[last() + 1]', APACHE_CONFIGURATION) - aug.load() - - aug.defvar('conf', '/files' + APACHE_CONFIGURATION) - - return aug - - -def subcommand_add(arguments): - """Add a share to Apache configuration.""" - name = arguments.name - path = '"' + arguments.path.replace('"', r'\"') + '"' - groups = arguments.groups - is_public = arguments.is_public - url = '/share/' + name - - if not os.path.exists(APACHE_CONFIGURATION): - pathlib.Path(APACHE_CONFIGURATION).touch() - - aug = load_augeas() - shares = _list(aug) - if any([share for share in shares if share['name'] == name]): - raise Exception('Share already present') - - aug.set('$conf/directive[last() + 1]', 'Alias') - aug.set('$conf/directive[last()]/arg[1]', url) - aug.set('$conf/directive[last()]/arg[2]', path) - - aug.set('$conf/Location[last() + 1]/arg', url) - - aug.set('$conf/Location[last()]/directive[last() + 1]', 'Include') - aug.set('$conf/Location[last()]/directive[last()]/arg', - 'includes/freedombox-sharing.conf') - - if not is_public: - aug.set('$conf/Location[last()]/directive[last() + 1]', 'Include') - aug.set('$conf/Location[last()]/directive[last()]/arg', - 'includes/freedombox-single-sign-on.conf') - - aug.set('$conf/Location[last()]/IfModule/arg', 'mod_auth_pubtkt.c') - aug.set('$conf/Location[last()]/IfModule/directive[1]', 'TKTAuthToken') - for group_name in groups: - aug.set( - '$conf/Location[last()]/IfModule/directive[1]/arg[last() + 1]', - group_name) - else: - aug.set('$conf/Location[last()]/directive[last() + 1]', 'Require') - aug.set('$conf/Location[last()]/directive[last()]/arg[1]', 'all') - aug.set('$conf/Location[last()]/directive[last()]/arg[2]', 'granted') - - aug.save() - - with action_utils.WebserverChange() as webserver_change: - webserver_change.enable('sharing-freedombox') - - -def subcommand_remove(arguments): - """Remove a share from Apache configuration.""" - url_to_remove = '/share/' + arguments.name - - aug = load_augeas() - - for directive in aug.match('$conf/directive'): - if aug.get(directive) != 'Alias': - continue - - url = aug.get(directive + '/arg[1]') - if url == url_to_remove: - aug.remove(directive) - - for location in aug.match('$conf/Location'): - url = aug.get(location + '/arg') - if url == url_to_remove: - aug.remove(location) - - aug.save() - - with action_utils.WebserverChange() as webserver_change: - webserver_change.enable('sharing-freedombox') - - -def _get_name_from_url(url): - """Return the name of the share given the URL for it.""" - matches = re.match(r'/share/([a-z0-9\-]*)', url) - if not matches: - raise ValueError - - return matches[1] - - -def _list(aug=None): - """List all Apache configuration shares.""" - if not aug: - aug = load_augeas() - - shares = [] - - for match in aug.match('$conf/directive'): - if aug.get(match) != 'Alias': - continue - - url = aug.get(match + '/arg[1]') - path = aug.get(match + '/arg[2]') - - path = path.removesuffix('"').removeprefix('"') - path = path.replace(r'\"', '"') - try: - name = _get_name_from_url(url) - shares.append({ - 'name': name, - 'path': path, - 'url': '/share/' + name - }) - except ValueError: - continue - - for location in aug.match('$conf/Location'): - url = aug.get(location + '/arg') - - try: - name = _get_name_from_url(url) - except ValueError: - continue - - groups = [] - for group in aug.match(location + '//directive["TKTAuthToken"]/arg'): - groups.append(aug.get(group)) - - def _is_public(): - """Must contain the line 'Require all granted'.""" - require = location + '//directive["Require"]' - return bool(aug.match(require)) and aug.get( - require + - '/arg[1]') == 'all' and aug.get(require + - '/arg[2]') == 'granted' - - for share in shares: - if share['name'] == name: - share['groups'] = groups - share['is_public'] = _is_public() - - return shares - - -def subcommand_list(_): - """List all Apache configuration shares and print as JSON.""" - print(json.dumps({'shares': _list()})) - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/sharing/__init__.py b/plinth/modules/sharing/__init__.py index 1ce644648..6a0c53e9e 100644 --- a/plinth/modules/sharing/__init__.py +++ b/plinth/modules/sharing/__init__.py @@ -1,13 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure sharing. -""" - -import json +"""FreedomBox app to configure sharing.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, menu from plinth.modules.apache.components import Webserver @@ -60,22 +55,3 @@ class SharingApp(app_module.App): super().setup(old_version) privileged.setup() self.enable() - - -def list_shares(): - """Return a list of shares.""" - output = actions.superuser_run('sharing', ['list']) - return json.loads(output)['shares'] - - -def add_share(name, path, groups, is_public): - """Add a new share by called the action script.""" - args = ['add', '--name', name, '--path', path, '--groups'] + groups - if is_public: - args.append('--is-public') - actions.superuser_run('sharing', args) - - -def remove_share(name): - """Remove a share by calling the action script.""" - actions.superuser_run('sharing', ['remove', '--name', name]) diff --git a/plinth/modules/sharing/forms.py b/plinth/modules/sharing/forms.py index e9a50a8c3..1416a0e27 100644 --- a/plinth/modules/sharing/forms.py +++ b/plinth/modules/sharing/forms.py @@ -1,15 +1,14 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Django forms for sharing app. -""" +"""Django forms for sharing app.""" from django import forms from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ -from plinth.modules import sharing from plinth.modules.users.components import UsersAndGroups +from . import privileged + class AddShareForm(forms.Form): """Form to add a new share.""" @@ -47,7 +46,7 @@ class AddShareForm(forms.Form): if 'name' in self.initial and name == self.initial['name']: return name - if any((share for share in sharing.list_shares() + if any((share for share in privileged.list_shares() if name == share['name'])): raise ValidationError(_('A share with this name already exists.')) diff --git a/plinth/modules/sharing/privileged.py b/plinth/modules/sharing/privileged.py index 79c247f07..bfc2745ec 100644 --- a/plinth/modules/sharing/privileged.py +++ b/plinth/modules/sharing/privileged.py @@ -1,8 +1,13 @@ # SPDX-License-Identifier: AGPL-3.0-or-later """Configure sharing.""" +import os import pathlib +import re +import augeas + +from plinth import action_utils from plinth.actions import privileged APACHE_CONFIGURATION = '/etc/apache2/conf-available/sharing-freedombox.conf' @@ -14,3 +19,157 @@ def setup(): path = pathlib.Path(APACHE_CONFIGURATION) if not path.exists(): path.touch() + + +def load_augeas(): + """Initialize augeas for this app's configuration file.""" + aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + + augeas.Augeas.NO_MODL_AUTOLOAD) + aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') + aug.set('/augeas/load/Httpd/incl[last() + 1]', APACHE_CONFIGURATION) + aug.load() + + aug.defvar('conf', '/files' + APACHE_CONFIGURATION) + + return aug + + +@privileged +def add(name: str, path: str, groups: list[str], is_public: bool): + """Add a share to Apache configuration.""" + path = '"' + path.replace('"', r'\"') + '"' + url = '/share/' + name + + if not os.path.exists(APACHE_CONFIGURATION): + pathlib.Path(APACHE_CONFIGURATION).touch() + + aug = load_augeas() + shares = _list(aug) + if any([share for share in shares if share['name'] == name]): + raise Exception('Share already present') + + aug.set('$conf/directive[last() + 1]', 'Alias') + aug.set('$conf/directive[last()]/arg[1]', url) + aug.set('$conf/directive[last()]/arg[2]', path) + + aug.set('$conf/Location[last() + 1]/arg', url) + + aug.set('$conf/Location[last()]/directive[last() + 1]', 'Include') + aug.set('$conf/Location[last()]/directive[last()]/arg', + 'includes/freedombox-sharing.conf') + + if not is_public: + aug.set('$conf/Location[last()]/directive[last() + 1]', 'Include') + aug.set('$conf/Location[last()]/directive[last()]/arg', + 'includes/freedombox-single-sign-on.conf') + + aug.set('$conf/Location[last()]/IfModule/arg', 'mod_auth_pubtkt.c') + aug.set('$conf/Location[last()]/IfModule/directive[1]', 'TKTAuthToken') + for group_name in groups: + aug.set( + '$conf/Location[last()]/IfModule/directive[1]/arg[last() + 1]', + group_name) + else: + aug.set('$conf/Location[last()]/directive[last() + 1]', 'Require') + aug.set('$conf/Location[last()]/directive[last()]/arg[1]', 'all') + aug.set('$conf/Location[last()]/directive[last()]/arg[2]', 'granted') + + aug.save() + + with action_utils.WebserverChange() as webserver_change: + webserver_change.enable('sharing-freedombox') + + +@privileged +def remove(name: str): + """Remove a share from Apache configuration.""" + url_to_remove = '/share/' + name + + aug = load_augeas() + + for directive in aug.match('$conf/directive'): + if aug.get(directive) != 'Alias': + continue + + url = aug.get(directive + '/arg[1]') + if url == url_to_remove: + aug.remove(directive) + + for location in aug.match('$conf/Location'): + url = aug.get(location + '/arg') + if url == url_to_remove: + aug.remove(location) + + aug.save() + + with action_utils.WebserverChange() as webserver_change: + webserver_change.enable('sharing-freedombox') + + +def _get_name_from_url(url): + """Return the name of the share given the URL for it.""" + matches = re.match(r'/share/([a-z0-9\-]*)', url) + if not matches: + raise ValueError + + return matches[1] + + +def _list(aug=None): + """List all Apache configuration shares.""" + if not aug: + aug = load_augeas() + + shares = [] + + for match in aug.match('$conf/directive'): + if aug.get(match) != 'Alias': + continue + + url = aug.get(match + '/arg[1]') + path = aug.get(match + '/arg[2]') + + path = path.removesuffix('"').removeprefix('"') + path = path.replace(r'\"', '"') + try: + name = _get_name_from_url(url) + shares.append({ + 'name': name, + 'path': path, + 'url': '/share/' + name + }) + except ValueError: + continue + + for location in aug.match('$conf/Location'): + url = aug.get(location + '/arg') + + try: + name = _get_name_from_url(url) + except ValueError: + continue + + groups = [] + for group in aug.match(location + '//directive["TKTAuthToken"]/arg'): + groups.append(aug.get(group)) + + def _is_public(): + """Must contain the line 'Require all granted'.""" + require = location + '//directive["Require"]' + return bool(aug.match(require)) and aug.get( + require + + '/arg[1]') == 'all' and aug.get(require + + '/arg[2]') == 'granted' + + for share in shares: + if share['name'] == name: + share['groups'] = groups + share['is_public'] = _is_public() + + return shares + + +@privileged +def list_shares() -> list[dict[str, object]]: + """List all Apache configuration shares and print as JSON.""" + return _list() diff --git a/plinth/modules/sharing/views.py b/plinth/modules/sharing/views.py index e317244fd..28d75deff 100644 --- a/plinth/modules/sharing/views.py +++ b/plinth/modules/sharing/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the sharing app. -""" +"""Views for the sharing app.""" from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin @@ -12,26 +10,28 @@ from django.utils.translation import gettext_lazy as _ from django.views.decorators.http import require_POST from django.views.generic import FormView -from plinth.modules import sharing from plinth.views import AppView +from . import privileged from .forms import AddShareForm class SharingAppView(AppView): """Sharing configuration page.""" + app_id = 'sharing' template_name = 'sharing.html' def get_context_data(self, **kwargs): """Return additional context for rendering the template.""" context = super().get_context_data(**kwargs) - context['shares'] = sharing.list_shares() + context['shares'] = privileged.list_shares() return context class AddShareView(SuccessMessageMixin, FormView): """View to add a new share.""" + form_class = AddShareForm prefix = 'sharing' template_name = 'sharing_add_edit.html' @@ -52,6 +52,7 @@ class AddShareView(SuccessMessageMixin, FormView): class EditShareView(SuccessMessageMixin, FormView): """View to edit an existing share.""" + form_class = AddShareForm prefix = 'sharing' template_name = 'sharing_add_edit.html' @@ -68,7 +69,7 @@ class EditShareView(SuccessMessageMixin, FormView): """Load information about share being edited.""" try: return [ - share for share in sharing.list_shares() + share for share in privileged.list_shares() if share['name'] == self.kwargs['name'] ][0] except IndexError: @@ -77,20 +78,20 @@ class EditShareView(SuccessMessageMixin, FormView): def form_valid(self, form): """Add the share on valid form submission.""" if form.initial != form.cleaned_data: - sharing.remove_share(form.initial['name']) + privileged.remove(form.initial['name']) _add_share(form.cleaned_data) return super().form_valid(form) def _add_share(form_data): - sharing.add_share(form_data['name'], form_data['path'], - form_data['groups'], form_data['is_public']) + privileged.add(form_data['name'], form_data['path'], form_data['groups'], + form_data['is_public']) @require_POST def remove(request, name): """View to remove a share.""" - sharing.remove_share(name) + privileged.remove(name) messages.success(request, _('Share deleted.')) return redirect(reverse_lazy('sharing:index')) From 8bdb73df9a23c7cbf4c524c7713348c0d9b6ccf9 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 2 Sep 2022 17:08:33 -0700 Subject: [PATCH 54/90] snapshot: Use privileged decorator for actions Tests: - DONE: Functional tests work - DONE: Initial setup work on btrfs filesystem - Not tested: Upgrading from older versions - DONE: After backup is restored for snapshot app, snapper daemon is reloaded - DONE: All configuration values are updated as expected - DONE: Values show up correctly in app page - DONE: Configuration files contain the proper values - DONE: New snapshot can be created, gets listed in the snapshots list - DONE: Enabling/disabling apt snapshotting works - DONE: Configuration file is updated - DONE: App page shows the correct value - DONE: Deleting snapshots works, snapshot is removed from the list - FAIL: Rolling back snapshots works (#2144) Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/upgrades | 18 +-- plinth/modules/snapshot/__init__.py | 18 +-- .../modules/snapshot/privileged.py | 106 ++++++------------ plinth/modules/snapshot/views.py | 37 +++--- 4 files changed, 62 insertions(+), 117 deletions(-) rename actions/snapshot => plinth/modules/snapshot/privileged.py (72%) mode change 100755 => 100644 diff --git a/actions/upgrades b/actions/upgrades index 3365f991b..d5e7960f8 100755 --- a/actions/upgrades +++ b/actions/upgrades @@ -432,15 +432,18 @@ def _take_snapshot_and_disable() -> bool: Return whether snapshots shall be re-enabled at the end.""" if snapshot_is_supported(): print('Taking a snapshot before dist upgrade...', flush=True) - subprocess.run(['/usr/share/plinth/actions/snapshot', 'create'], - check=True) + subprocess.run([ + '/usr/share/plinth/actions/actions', 'snapshot', 'create', + '--no-args' + ], check=True) aug = snapshot_load_augeas() if is_apt_snapshots_enabled(aug): print('Disable apt snapshots during dist upgrade...', flush=True) subprocess.run([ - '/usr/share/plinth/actions/snapshot', 'disable-apt-snapshot', - 'yes' - ], check=True) + '/usr/share/plinth/actions/actions', + 'snapshot', + 'disable_apt_snapshot', + ], input='{"args": ["yes"], "kwargs": {}}'.encode(), check=True) return True else: print('Apt snapshots already disabled.', flush=True) @@ -456,8 +459,9 @@ def _restore_snapshots_config(reenable=False): if reenable: print('Re-enable apt snapshots...', flush=True) subprocess.run([ - '/usr/share/plinth/actions/snapshot', 'disable-apt-snapshot', 'no' - ], check=True) + '/usr/share/plinth/actions/actions', 'snapshot', + 'disable_apt_snapshot' + ], input='{"args": ["no"], "kwargs": {}}'.encode(), check=True) def _disable_searx() -> bool: diff --git a/plinth/modules/snapshot/__init__.py b/plinth/modules/snapshot/__init__.py index c16ccb4d6..d1e6ddf4d 100644 --- a/plinth/modules/snapshot/__init__.py +++ b/plinth/modules/snapshot/__init__.py @@ -1,22 +1,18 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to manage filesystem snapshots. -""" +"""FreedomBox app to manage filesystem snapshots.""" -import json import pathlib import augeas from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import menu from plinth.modules import storage from plinth.modules.backups.components import BackupRestore from plinth.package import Packages -from . import manifest +from . import manifest, privileged _description = [ _('Snapshots allows creating and managing btrfs file system snapshots. ' @@ -71,9 +67,7 @@ class SnapshotApp(app_module.App): """Install and configure the app.""" super().setup(old_version) if is_supported(): - actions.superuser_run('snapshot', - ['setup', '--old-version', - str(old_version)]) + privileged.setup(old_version) self.enable() @@ -82,7 +76,7 @@ class SnapshotBackupRestore(BackupRestore): def restore_post(self, packet): """Run after restore.""" - actions.superuser_run('snapshot', ['kill-daemon']) + privileged.kill_daemon() def is_supported(): @@ -114,9 +108,9 @@ def is_apt_snapshots_enabled(aug): def get_configuration(): + """Return snapper configuration.""" aug = load_augeas() - output = actions.superuser_run('snapshot', ['get-config']) - output = json.loads(output) + output = privileged.get_config() def get_boolean_choice(status): return ('yes', 'Enabled') if status else ('no', 'Disabled') diff --git a/actions/snapshot b/plinth/modules/snapshot/privileged.py old mode 100755 new mode 100644 similarity index 72% rename from actions/snapshot rename to plinth/modules/snapshot/privileged.py index f74513089..f0d18e24a --- a/actions/snapshot +++ b/plinth/modules/snapshot/privileged.py @@ -1,11 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for filesystem snapshots. -""" +"""Configuration helper for filesystem snapshots.""" -import argparse -import json import os import signal import subprocess @@ -13,46 +8,15 @@ import subprocess import augeas import dbus +from plinth.actions import privileged + FSTAB = '/etc/fstab' AUG_FSTAB = '/files/etc/fstab' DEFAULT_FILE = '/etc/default/snapper' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparser = subparsers.add_parser('setup', help='Configure snapper') - subparser.add_argument( - '--old-version', type=int, required=True, - help='Earlier version of the app that is already setup.') - subparsers.add_parser('list', help='List snapshots') - subparsers.add_parser('create', help='Create snapshot') - subparsers.add_parser('get-config', help='Configurations of snapshot') - - subparser = subparsers.add_parser('delete', - help='Delete a snapshot by number') - subparser.add_argument('number', help='Number of snapshot to delete') - - subparser = subparsers.add_parser('set-config', - help='Configure automatic snapshots') - subparser.add_argument('config') - subparsers.add_parser('kill-daemon', - help='Kill snapperd to reload configuration') - - subparser = subparsers.add_parser('rollback', help='Rollback to snapshot') - subparser.add_argument('number', help='Number of snapshot to rollback to') - - subparser = subparsers.add_parser('disable-apt-snapshot', - help='enable/disable apt snapshots') - subparser.add_argument('state') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_setup(arguments): +@privileged +def setup(old_version: int): """Configure snapper.""" # Check if root config exists. command = ['snapper', 'list-configs'] @@ -65,9 +29,9 @@ def subcommand_setup(arguments): subprocess.run(command, check=True) _add_fstab_entry('/') - if arguments.old_version == 0: + if old_version == 0: _set_default_config() - elif arguments.old_version <= 3: + elif old_version <= 3: _migrate_config_from_version_3() else: pass # After version 4 and above don't reset configuration @@ -170,7 +134,8 @@ def _parse_number(number): return number.strip('-+*'), is_default, is_active -def subcommand_list(_): +@privileged +def list_() -> list[dict[str, str]]: """List snapshots.""" process = subprocess.run(['snapper', 'list'], stdout=subprocess.PIPE, check=True) @@ -189,7 +154,7 @@ def subcommand_list(_): snapshots.append(snapshot) snapshots.reverse() - print(json.dumps(snapshots)) + return snapshots def _get_default_snapshot(): @@ -208,8 +173,9 @@ def _get_default_snapshot(): return None -def subcommand_disable_apt_snapshot(arguments): - """Set flag to Enable/Disable apt software snapshots in config files""" +@privileged +def disable_apt_snapshot(state: str): + """Set flag to Enable/Disable apt software snapshots in config files.""" # Initialize Augeas aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) @@ -217,24 +183,28 @@ def subcommand_disable_apt_snapshot(arguments): aug.set('/augeas/load/Shellvars/incl[last() + 1]', DEFAULT_FILE) aug.load() - aug.set('/files' + DEFAULT_FILE + '/DISABLE_APT_SNAPSHOT', arguments.state) + aug.set('/files' + DEFAULT_FILE + '/DISABLE_APT_SNAPSHOT', state) aug.save() -def subcommand_create(_): +@privileged +def create(): """Create snapshot.""" command = ['snapper', 'create', '--description', 'manually created'] subprocess.run(command, check=True) -def subcommand_delete(arguments): +@privileged +def delete(number: str): """Delete a snapshot by number.""" - command = ['snapper', 'delete', arguments.number] + command = ['snapper', 'delete', number] subprocess.run(command, check=True) -def subcommand_set_config(arguments): - command = ['snapper', 'set-config'] + arguments.config.split() +@privileged +def set_config(config: list[str]): + """Set snapper configuration.""" + command = ['snapper', 'set-config'] + config subprocess.run(command, check=True) @@ -249,12 +219,14 @@ def _get_config(): return config -def subcommand_get_config(_): - config = _get_config() - print(json.dumps(config)) +@privileged +def get_config() -> dict[str, str]: + """Return snapper configuration.""" + return _get_config() -def subcommand_kill_daemon(_): +@privileged +def kill_daemon(): """Kill the snapper daemon. This is generally not necessary because we do configuration changes via @@ -262,7 +234,6 @@ def subcommand_kill_daemon(_): need to kill the daemon to reload configuration. Ideally, we should be able to reload/terminate the service using systemd. - """ bus = dbus.SystemBus() @@ -277,23 +248,10 @@ def subcommand_kill_daemon(_): os.kill(pid, signal.SIGTERM) -def subcommand_rollback(arguments): +@privileged +def rollback(number: str): """Rollback to snapshot.""" command = [ - 'snapper', 'rollback', '--description', 'created by rollback', - arguments.number + 'snapper', 'rollback', '--description', 'created by rollback', number ] subprocess.run(command, check=True) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/snapshot/views.py b/plinth/modules/snapshot/views.py index e40df217a..86f892f76 100644 --- a/plinth/modules/snapshot/views.py +++ b/plinth/modules/snapshot/views.py @@ -1,9 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for snapshot module. -""" +"""Views for snapshot module.""" -import json import urllib.parse from django.contrib import messages @@ -14,14 +11,12 @@ from django.urls import reverse, reverse_lazy from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy -from plinth import actions from plinth import app as app_module -from plinth.errors import ActionError from plinth.modules import snapshot as snapshot_module from plinth.modules import storage from plinth.views import AppView -from . import get_configuration +from . import get_configuration, privileged from .forms import SnapshotForm # i18n for snapshot descriptions @@ -90,7 +85,7 @@ def manage(request): if request.method == 'POST': if 'create' in request.POST: - actions.superuser_run('snapshot', ['create']) + privileged.create() messages.success(request, _('Created snapshot.')) if 'delete_selected' in request.POST: to_delete = request.POST.getlist('snapshot_list') @@ -102,8 +97,7 @@ def manage(request): url = reverse('snapshot:delete-selected') return HttpResponseRedirect(f'{url}?{params}') - output = actions.superuser_run('snapshot', ['list']) - snapshots = json.loads(output) + snapshots = privileged.list_() has_deletable_snapshots = any([ snapshot for snapshot in snapshots if not snapshot['is_default'] and not snapshot['is_active'] @@ -148,15 +142,14 @@ def update_configuration(request, old_status, new_status): if old_status['enable_software_snapshots'] != new_status[ 'enable_software_snapshots']: if new_status['enable_software_snapshots'] == 'yes': - actions.superuser_run('snapshot', ['disable-apt-snapshot', 'no']) + privileged.disable_apt_snapshot('no') else: - actions.superuser_run('snapshot', ['disable-apt-snapshot', 'yes']) + privileged.disable_apt_snapshot('yes') try: - actions.superuser_run('snapshot', ['set-config', " ".join(config)]) - + privileged.set_config(list(config)) messages.success(request, _('Storage snapshots configuration updated')) - except ActionError as exception: + except Exception as exception: messages.error( request, _('Action error: {0} [{1}] [{2}]').format(exception.args[0], @@ -174,8 +167,7 @@ def delete_selected(request): if not to_delete: return redirect(reverse('snapshot:manage')) - output = actions.superuser_run('snapshot', ['list']) - snapshots = json.loads(output) + snapshots = privileged.list_() snapshots_to_delete = [ snapshot for snapshot in snapshots if snapshot['number'] in to_delete and not snapshot['is_active'] and not snapshot['is_default'] @@ -184,11 +176,10 @@ def delete_selected(request): if request.method == 'POST': try: for snapshot in snapshots_to_delete: - actions.superuser_run('snapshot', - ['delete', snapshot['number']]) + privileged.delete(snapshot['number']) messages.success(request, _('Deleted selected snapshots')) - except ActionError as exception: + except Exception as exception: if 'Config is in use.' in exception.args[2]: messages.error( request, @@ -208,7 +199,7 @@ def delete_selected(request): def rollback(request, number): """Show confirmation to rollback to a snapshot.""" if request.method == 'POST': - actions.superuser_run('snapshot', ['rollback', number]) + privileged.rollback(number) messages.success( request, _('Rolled back to snapshot #{number}.').format(number=number)) @@ -217,9 +208,7 @@ def rollback(request, number): _('The system must be restarted to complete the rollback.')) return redirect(reverse('power:restart')) - output = actions.superuser_run('snapshot', ['list']) - snapshots = json.loads(output) - + snapshots = privileged.list_() snapshot = None for current_snapshot in snapshots: if current_snapshot['number'] == number: From 12cf5065b07d03bdbf3931c54643ef7e286a1c82 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 14:14:57 -0700 Subject: [PATCH 55/90] ssh: Use privileged decorator for actions Tests: - Functional tests work - Updating SSH keys in user edit page sets the SSH keys. File is updated properly. Page shows newly set SSH keys. - Entering invalid auth credentials throws error - Enabling/disabling SSH password authentication works. - Configuration file is updated. - App page shows proper value Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/ssh/__init__.py | 15 +-- .../ssh => plinth/modules/ssh/privileged.py | 106 +++++------------- plinth/modules/ssh/views.py | 30 +++-- plinth/modules/users/forms.py | 15 +-- plinth/modules/users/views.py | 6 +- 5 files changed, 51 insertions(+), 121 deletions(-) rename actions/ssh => plinth/modules/ssh/privileged.py (52%) mode change 100755 => 100644 diff --git a/plinth/modules/ssh/__init__.py b/plinth/modules/ssh/__init__.py index 13e358aa6..e5e40a6dc 100644 --- a/plinth/modules/ssh/__init__.py +++ b/plinth/modules/ssh/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for OpenSSH server. -""" +"""FreedomBox app for OpenSSH server.""" import pathlib import re @@ -9,7 +7,6 @@ import subprocess from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import menu from plinth.daemon import Daemon @@ -17,7 +14,7 @@ from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.package import Packages -from . import manifest +from . import manifest, privileged _description = [ _('A Secure Shell server uses the secure shell protocol to accept ' @@ -65,7 +62,7 @@ class SSHApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('ssh', ['setup']) + privileged.setup() self.enable() @@ -87,9 +84,3 @@ def get_host_keys(): host_keys.append(match.groupdict()) return host_keys - - -def is_password_authentication_disabled(): - """Return if ssh password authentication is enabled.""" - return actions.superuser_run('ssh', - ['get-password-config']).strip() == 'no' diff --git a/actions/ssh b/plinth/modules/ssh/privileged.py old mode 100755 new mode 100644 similarity index 52% rename from actions/ssh rename to plinth/modules/ssh/privileged.py index acf0d5fea..ee95983b0 --- a/actions/ssh +++ b/plinth/modules/ssh/privileged.py @@ -1,52 +1,20 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for SSH server. -""" +"""Configuration helper for SSH server.""" -import argparse import grp import os import pwd import shutil import stat import subprocess -import sys import augeas from plinth import action_utils, utils +from plinth.actions import privileged -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Setup SSH server') - - get_keys = subparsers.add_parser('get-keys', - help='Get SSH authorized keys') - get_keys.add_argument('--username', required=True, type=_managed_user) - - set_keys = subparsers.add_parser('set-keys', - help='Set SSH authorized keys') - set_keys.add_argument('--username', required=True, type=_managed_user) - set_keys.add_argument('--keys', required=True) - set_keys.add_argument('--auth-user', required=True) - - subparsers.add_parser('get-password-config', - help='Get SSH password auth configuration') - - set_password_config = subparsers.add_parser( - 'set-password-config', help='Set SSH password auth configuration') - set_password_config.add_argument('--value') - - subparsers.required = True - return parser.parse_args() - - -def _validate_user(username, must_be_admin=True): +def _validate_user(username, password, must_be_admin=True): """Validate a user.""" if must_be_admin: try: @@ -55,29 +23,23 @@ def _validate_user(username, must_be_admin=True): admins = [] if username not in admins: - msg = '"{}" is not authorized to perform this action'.format( - username) - raise argparse.ArgumentTypeError(msg) + msg = f'"{username}" is not authorized to perform this action' + raise PermissionError(msg) - password = _read_password() if not utils.is_authenticated_user(username, password): - raise argparse.ArgumentTypeError("Invalid credentials") + raise PermissionError('Invalid credentials') def _managed_user(username): """Raise an error if the user is root.""" if pwd.getpwnam(username).pw_gid == 0: - msg = 'User {} is not managed by FreedomBox'.format(username) - raise argparse.ArgumentTypeError(msg) + raise ValueError(f'User {username} is not managed by FreedomBox') + return username -def _read_password(): - """Read the password from stdin.""" - return ''.join(sys.stdin) - - -def subcommand_setup(arguments): +@privileged +def setup(): """Setup Open SSH server. Regenerates deleted SSH keys. This is necessary when FreedomBox image is @@ -87,7 +49,6 @@ def subcommand_setup(arguments): If the keys already exist, do nothing. This is necessary when a user installs FreedomBox using an apt package. SSH keys exist and running reconfigure on the openssh-server package does not regenerate them. - """ action_utils.dpkg_reconfigure('openssh-server', {}) @@ -97,29 +58,25 @@ def get_user_homedir(username): try: return pwd.getpwnam(username).pw_dir except KeyError: - print('Username not found') - sys.exit(1) + raise ValueError('Username not found') -def subcommand_get_keys(arguments): +@privileged +def get_keys(user: str) -> str: """Get SSH authorized keys.""" - user = arguments.username - path = os.path.join(get_user_homedir(user), '.ssh', 'authorized_keys') try: with open(path, 'r', encoding='utf-8') as file_handle: - print(file_handle.read()) + return file_handle.read() except FileNotFoundError: - pass + return '' -def subcommand_set_keys(arguments): +@privileged +def set_keys(user: str, keys: str, auth_user: str, auth_password: str): """Set SSH authorized keys.""" - user = arguments.username - auth_user = arguments.auth_user - must_be_admin = user != auth_user - _validate_user(auth_user, must_be_admin=must_be_admin) + _validate_user(auth_user, auth_password, must_be_admin=must_be_admin) ssh_folder = os.path.join(get_user_homedir(user), '.ssh') key_file_path = os.path.join(ssh_folder, 'authorized_keys') @@ -131,7 +88,7 @@ def subcommand_set_keys(arguments): shutil.chown(ssh_folder, user, 'users') with open(key_file_path, 'w', encoding='utf-8') as file_handle: - file_handle.write(arguments.keys) + file_handle.write(keys) shutil.chown(key_file_path, user, 'users') os.chmod(key_file_path, stat.S_IRUSR | stat.S_IWUSR) @@ -148,30 +105,19 @@ def _load_augeas(): return aug -def subcommand_get_password_config(_): +@privileged +def is_password_authentication_enabled() -> bool: """Retrieve value of password authentication from sshd configuration.""" aug = _load_augeas() field_path = '/files/etc/ssh/sshd_config/PasswordAuthentication' get_value = aug.get(field_path) - print(get_value or 'yes') + return (get_value or 'yes') == 'yes' -def subcommand_set_password_config(arguments): +@privileged +def set_password_authentication(enable: bool): """Set value of password authentication in sshd configuration.""" + value = 'yes' if enable else 'no' aug = _load_augeas() - aug.set('/files/etc/ssh/sshd_config/PasswordAuthentication', - arguments.value) + aug.set('/files/etc/ssh/sshd_config/PasswordAuthentication', value) aug.save() - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/ssh/views.py b/plinth/modules/ssh/views.py index ebddcf3d3..d35c0b0ec 100644 --- a/plinth/modules/ssh/views.py +++ b/plinth/modules/ssh/views.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the SSH module -""" +"""Views for the SSH app.""" + from django.contrib import messages from django.utils.translation import gettext_lazy as _ @@ -9,32 +8,36 @@ from plinth import actions from plinth.modules import ssh from plinth.views import AppView -from . import is_password_authentication_disabled +from . import privileged from .forms import SSHServerForm class SshAppView(AppView): + """Show ssh app main page.""" + app_id = 'ssh' template_name = 'ssh.html' form_class = SSHServerForm def get_context_data(self, *args, **kwargs): + """Return additional context for rendering the template.""" context = super().get_context_data(**kwargs) context['host_keys'] = ssh.get_host_keys() return context def get_initial(self): - """Initial form value""" + """Return initial values of the form.""" initial = super().get_initial() initial.update({ - 'password_auth_disabled': is_password_authentication_disabled(), + 'password_auth_disabled': + not privileged.is_password_authentication_enabled(), }) return initial def form_valid(self, form): - """Apply changes from the form""" + """Apply changes from the form.""" old_config = self.get_initial() new_config = form.cleaned_data @@ -43,16 +46,9 @@ class SshAppView(AppView): passwd_auth_changed = is_field_changed('password_auth_disabled') if passwd_auth_changed: - if new_config['password_auth_disabled']: - passwd_auth = 'no' - message = _('SSH authentication with password disabled.') - else: - passwd_auth = 'yes' - message = _('SSH authentication with password enabled.') - - actions.superuser_run( - 'ssh', ['set-password-config', '--value', passwd_auth]) + privileged.set_password_authentication( + not new_config['password_auth_disabled']) actions.superuser_run('service', ['reload', 'ssh']) - messages.success(self.request, message) + messages.success(self.request, _('Configuration updated')) return super().form_valid(form) diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py index 5dd6b7a74..76747a9c2 100644 --- a/plinth/modules/users/forms.py +++ b/plinth/modules/users/forms.py @@ -15,6 +15,7 @@ from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy import plinth.forms +import plinth.modules.ssh.privileged as ssh_privileged from plinth import actions from plinth.errors import ActionError from plinth.modules import first_boot @@ -294,16 +295,10 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, _('Failed to add user to group.')) try: - actions.superuser_run('ssh', [ - 'set-keys', - '--username', - user.get_username(), - '--keys', - self.cleaned_data['ssh_keys'].strip(), - '--auth-user', - auth_username, - ], input=confirm_password.encode()) - except ActionError: + ssh_privileged.set_keys(user.get_username(), + self.cleaned_data['ssh_keys'].strip(), + auth_username, confirm_password) + except Exception: messages.error(self.request, _('Unable to set SSH keys.')) is_active = self.cleaned_data['is_active'] diff --git a/plinth/modules/users/views.py b/plinth/modules/users/views.py index 7d25fe518..005701299 100644 --- a/plinth/modules/users/views.py +++ b/plinth/modules/users/views.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later +"""Django views for user app.""" import django.views.generic from django.contrib import messages @@ -13,6 +14,7 @@ from django.utils.translation import gettext_lazy from django.views.generic.edit import (CreateView, DeleteView, FormView, UpdateView) +import plinth.modules.ssh.privileged as ssh_privileged from plinth import actions, translation from plinth.errors import ActionError from plinth.modules import first_boot @@ -36,6 +38,7 @@ class ContextMixin: class UserCreate(ContextMixin, SuccessMessageMixin, CreateView): """View to create a new user.""" + form_class = CreateUserForm template_name = 'users_create.html' model = User @@ -95,8 +98,7 @@ class UserUpdate(ContextMixin, SuccessMessageMixin, UpdateView): """Return the data for initial form load.""" initial = super().get_initial() try: - ssh_keys = actions.superuser_run( - 'ssh', ['get-keys', '--username', self.object.username]) + ssh_keys = ssh_privileged.get_keys(self.object.username) initial['ssh_keys'] = ssh_keys.strip() initial['language'] = self.object.userprofile.language except ActionError: From 6ea08fb93f33f82e52fe5998c96c7eb7f6eaa523 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 14:31:11 -0700 Subject: [PATCH 56/90] sso: Use privileged decorator for actions Tests: - Functional tests succeed - Initial setup run during first setup successfully - A key pair is created in /etc/apache2/auth-pubtkt-keys - User is able successfully login to web UI. - A non-admin user who has permission to access an app via group membership is able to access the app's web interface. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/sso/__init__.py | 10 +-- .../modules/sso/privileged.py | 82 ++++++------------- .../{test_actions.py => test_privileged.py} | 25 +++--- plinth/modules/sso/views.py | 26 +++--- 4 files changed, 53 insertions(+), 90 deletions(-) rename actions/auth-pubtkt => plinth/modules/sso/privileged.py (50%) mode change 100755 => 100644 rename plinth/modules/sso/tests/{test_actions.py => test_privileged.py} (58%) diff --git a/plinth/modules/sso/__init__.py b/plinth/modules/sso/__init__.py index 8a3aeddb5..ed6e1a659 100644 --- a/plinth/modules/sso/__init__.py +++ b/plinth/modules/sso/__init__.py @@ -1,17 +1,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Single Sign On services. -""" +"""FreedomBox app to configure Single Sign On services.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth.package import Packages +from . import privileged + class SSOApp(app_module.App): """FreedomBox app for single sign on.""" + app_id = 'sso' _version = 1 @@ -34,4 +34,4 @@ class SSOApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('auth-pubtkt', ['create-key-pair']) + privileged.create_key_pair() diff --git a/actions/auth-pubtkt b/plinth/modules/sso/privileged.py old mode 100755 new mode 100644 similarity index 50% rename from actions/auth-pubtkt rename to plinth/modules/sso/privileged.py index bdf7f8f9c..4b7f3212a --- a/actions/auth-pubtkt +++ b/plinth/modules/sso/privileged.py @@ -1,44 +1,23 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Module with utilities to generate a auth_pubtkt ticket and -sign it with the FreedomBox server's private key. +"""Generate a auth_pubtkt ticket. + +Sign tickets with the FreedomBox server's private key. """ -import argparse import base64 import datetime import os from OpenSSL import crypto +from plinth.actions import privileged + KEYS_DIRECTORY = '/etc/apache2/auth-pubtkt-keys' -def parse_arguments(): - """ Return parsed command line arguments as dictionary. """ - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser( - 'create-key-pair', help='create a key pair for the apache server ' - 'to sign auth_pubtkt tickets') - gen_tkt = subparsers.add_parser('generate-ticket', - help='generate auth_pubtkt ticket') - gen_tkt.add_argument('--uid', help='username of the user') - gen_tkt.add_argument('--private-key-file', - help='path of the private key file of the server') - gen_tkt.add_argument('--tokens', - help='tokens, usually containing the user groups') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_create_key_pair(_): - """Create public/private key pair for signing the auth_pubtkt - tickets. - """ +@privileged +def create_key_pair(): + """Create public/private key pair for signing the tickets.""" private_key_file = os.path.join(KEYS_DIRECTORY, 'privkey.pem') public_key_file = os.path.join(KEYS_DIRECTORY, 'pubkey.pem') @@ -64,9 +43,10 @@ def subcommand_create_key_pair(_): os.chmod(fil, 0o440) -def create_ticket(pkey, uid, validuntil, ip=None, tokens=None, udata=None, - graceperiod=None, extra_fields=None): +def _create_ticket(pkey, uid, validuntil, ip=None, tokens=None, udata=None, + graceperiod=None, extra_fields=None): """Create and return a signed mod_auth_pubtkt ticket.""" + tokens = ','.join(tokens) fields = [ f'uid={uid}', f'validuntil={int(validuntil)}', @@ -78,49 +58,33 @@ def create_ticket(pkey, uid, validuntil, ip=None, tokens=None, udata=None, and ';'.join(['{}={}'.format(k, v) for k, v in extra_fields]), ] data = ';'.join(filter(None, fields)) - signature = 'sig={}'.format(sign(pkey, data)) + signature = 'sig={}'.format(_sign(pkey, data)) return ';'.join([data, signature]) -def sign(pkey, data): - """Calculates and returns ticket's signature.""" +def _sign(pkey, data): + """Calculate and return ticket's signature.""" sig = crypto.sign(pkey, data.encode(), 'sha512') return base64.b64encode(sig).decode() -def subcommand_generate_ticket(arguments): +@privileged +def generate_ticket(uid: str, private_key_file: str, tokens: list[str]) -> str: """Generate a mod_auth_pubtkt ticket using login credentials.""" - uid = arguments.uid - private_key_file = arguments.private_key_file - tokens = arguments.tokens with open(private_key_file, 'r', encoding='utf-8') as fil: pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, fil.read().encode()) - valid_until = minutes_from_now(12 * 60) - grace_period = minutes_from_now(11 * 60) - print( - create_ticket(pkey, uid, valid_until, tokens=tokens, - graceperiod=grace_period)) + valid_until = _minutes_from_now(12 * 60) + grace_period = _minutes_from_now(11 * 60) + return _create_ticket(pkey, uid, valid_until, tokens=tokens, + graceperiod=grace_period) -def minutes_from_now(minutes): +def _minutes_from_now(minutes): """Return a timestamp at the given number of minutes from now.""" - return seconds_from_now(minutes * 60) + return _seconds_from_now(minutes * 60) -def seconds_from_now(seconds): +def _seconds_from_now(seconds): """Return a timestamp at the given number of seconds from now.""" return (datetime.datetime.now() + datetime.timedelta(0, seconds)).timestamp() - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/sso/tests/test_actions.py b/plinth/modules/sso/tests/test_privileged.py similarity index 58% rename from plinth/modules/sso/tests/test_actions.py rename to plinth/modules/sso/tests/test_privileged.py index 147015a04..6b57168ba 100644 --- a/plinth/modules/sso/tests/test_actions.py +++ b/plinth/modules/sso/tests/test_privileged.py @@ -7,34 +7,33 @@ import os import pytest +from plinth.modules.sso import privileged from plinth.modules.sso.views import PRIVATE_KEY_FILE_NAME -actions_name = 'auth-pubtkt' +pytestmark = pytest.mark.usefixtures('mock_privileged') +privileged_modules_to_mock = ['plinth.modules.sso.privileged'] @pytest.fixture(autouse=True) -def fixture_keys_directory(actions_module, tmpdir): +def fixture_keys_directory(tmpdir): """Set keys directory in the actions module.""" - actions_module.KEYS_DIRECTORY = str(tmpdir) + privileged.KEYS_DIRECTORY = str(tmpdir) @pytest.fixture(name='existing_key_pair') -def fixture_existing_key_pair(call_action): +def fixture_existing_key_pair(): """A fixture to create key pair if needed.""" - call_action(['create-key-pair']) + privileged.create_key_pair() -def test_generate_ticket(call_action, existing_key_pair, actions_module): +def test_generate_ticket(existing_key_pair): """Test generating a ticket.""" username = 'tester' - groups = 'freedombox-share,syncthing,web-search' + groups = ['freedombox-share', 'syncthing', 'web-search'] - private_key_file = os.path.join(actions_module.KEYS_DIRECTORY, + private_key_file = os.path.join(privileged.KEYS_DIRECTORY, PRIVATE_KEY_FILE_NAME) - ticket = call_action([ - 'generate-ticket', '--uid', username, '--private-key-file', - private_key_file, '--tokens', groups - ]) + ticket = privileged.generate_ticket(username, private_key_file, groups) fields = {} for item in ticket.split(';'): @@ -47,5 +46,5 @@ def test_generate_ticket(call_action, existing_key_pair, actions_module): assert fields['uid'] == username assert int(fields['validuntil']) > 0 - assert fields['tokens'] == groups + assert fields['tokens'] == ','.join(groups) assert int(fields['graceperiod']) > 0 diff --git a/plinth/modules/sso/views.py b/plinth/modules/sso/views.py index 083d3eea7..006072aa9 100644 --- a/plinth/modules/sso/views.py +++ b/plinth/modules/sso/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for the Single Sign On app of FreedomBox. -""" +"""Views for the Single Sign On app of FreedomBox.""" import logging import os @@ -17,8 +15,9 @@ from django.contrib.auth.views import LoginView from django.http import HttpResponseRedirect from django.utils.translation import gettext as _ -from plinth import actions, translation, utils, web_framework +from plinth import translation, utils, web_framework +from . import privileged from .forms import AuthenticationForm, CaptchaAuthenticationForm PRIVATE_KEY_FILE_NAME = 'privkey.pem' @@ -29,15 +28,11 @@ logger = logging.getLogger(__name__) def set_ticket_cookie(user, response): - """Generate and set a mod_auth_pubtkt as a cookie in the provided - response. - """ + """Generate and set a mod_auth_pubtkt as a cookie in the response.""" tokens = list(map(lambda g: g.name, user.groups.all())) private_key_file = os.path.join(KEYS_DIRECTORY, PRIVATE_KEY_FILE_NAME) - ticket = actions.superuser_run('auth-pubtkt', [ - 'generate-ticket', '--uid', user.username, '--private-key-file', - private_key_file, '--tokens', ','.join(tokens) - ]) + ticket = privileged.generate_ticket(user.username, private_key_file, + tokens) response.set_cookie(SSO_COOKIE_NAME, urllib.parse.quote(ticket)) return response @@ -46,13 +41,14 @@ class SSOLoginView(LoginView): """View to login to FreedomBox and set a auth_pubtkt cookie. Cookie will be used to provide Single Sign On for some other applications. - """ + redirect_authenticated_user = True template_name = 'login.html' form_class = AuthenticationForm def dispatch(self, request, *args, **kwargs): + """Handle a request and return a HTTP response.""" response = super().dispatch(request, *args, **kwargs) if request.user.is_authenticated: translation.set_language(request, response, @@ -65,15 +61,19 @@ class SSOLoginView(LoginView): # axes_form_invalid when axes >= 5.0.0 becomes available in Debian stable. @axes_form_invalid def form_invalid(self, *args, **kwargs): + """Trigger django-axes logic to deal with too many attempts.""" return super().form_invalid(*args, **kwargs) class CaptchaLoginView(LoginView): + """A login view with mandatory CAPTCHA image.""" + redirect_authenticated_user = True template_name = 'login.html' form_class = CaptchaAuthenticationForm def dispatch(self, request, *args, **kwargs): + """Handle a request and return a HTTP response.""" response = super().dispatch(request, *args, **kwargs) if not request.POST: return response @@ -102,7 +102,7 @@ def logout(request): def refresh(request): - """Simulate cookie refresh - redirect logged in user with a new cookie""" + """Simulate cookie refresh - redirect logged in user with a new cookie.""" redirect_url = request.GET.get(REDIRECT_FIELD_NAME, '') response = HttpResponseRedirect(redirect_url) response.delete_cookie(SSO_COOKIE_NAME) From 317e83c38fcc2009a5156da55c49a1cf339c7d6a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 14:34:46 -0700 Subject: [PATCH 57/90] syncthing: Use privileged decorator for actions Tests: - Functional tests succeed (noticed intermittent failure) - Initial setup succeeds - User/group are created. /var/lib/syncthing is created with proper user/group ownership. - In configuration file, authentication notification is disabled - Syncthing web interface is accessible - Authentication related notification is not shown. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/syncthing/__init__.py | 11 ++--- .../modules/syncthing/privileged.py | 41 ++++--------------- 2 files changed, 11 insertions(+), 41 deletions(-) rename actions/syncthing => plinth/modules/syncthing/privileged.py (70%) mode change 100755 => 100644 diff --git a/plinth/modules/syncthing/__init__.py b/plinth/modules/syncthing/__init__.py index 2f0a9eb88..770883447 100644 --- a/plinth/modules/syncthing/__init__.py +++ b/plinth/modules/syncthing/__init__.py @@ -1,11 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Syncthing. -""" +"""FreedomBox app to configure Syncthing.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -17,7 +14,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('Syncthing is an application to synchronize files across multiple ' @@ -106,13 +103,13 @@ class SyncthingApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('syncthing', ['setup']) + privileged.setup() add_user_to_share_group(SYSTEM_USER, SyncthingApp.DAEMON) if not old_version: self.enable() - actions.superuser_run('syncthing', ['setup-config']) + privileged.setup_config() if old_version == 1 and self.is_enabled(): self.get_component('firewall-syncthing-ports').enable() diff --git a/actions/syncthing b/plinth/modules/syncthing/privileged.py old mode 100755 new mode 100644 similarity index 70% rename from actions/syncthing rename to plinth/modules/syncthing/privileged.py index 200dbb117..efa8c40f7 --- a/actions/syncthing +++ b/plinth/modules/syncthing/privileged.py @@ -1,10 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Syncthing. -""" +"""Configure Syncthing.""" -import argparse import grp import os import pwd @@ -15,24 +11,12 @@ import time import augeas from plinth import action_utils +from plinth.actions import privileged DATA_DIR = '/var/lib/syncthing' CONF_FILE = DATA_DIR + '/.config/syncthing/config.xml' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Setup Syncthing') - - subparsers.add_parser('setup-config', help='Setup Syncthing configuration') - - subparsers.required = True - return parser.parse_args() - - def augeas_load(): """Initialize Augeas.""" aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + @@ -42,8 +26,9 @@ def augeas_load(): return aug -def subcommand_setup(_): - """Actions to be performed before installing Syncthing""" +@privileged +def setup(): + """Perform post-install actions for Syncthing.""" # Create syncthing group if needed. try: grp.getgrnam('syncthing') @@ -65,7 +50,8 @@ def subcommand_setup(_): shutil.chown(DATA_DIR, user='syncthing', group='syncthing') -def subcommand_setup_config(_): +@privileged +def setup_config(): """Make configuration changes.""" # wait until the configuration file is created by the syncthing daemon timeout = 300 @@ -94,16 +80,3 @@ def subcommand_setup_config(_): if conf_changed: action_utils.service_try_restart('syncthing@syncthing') - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() From a78480c0335bc07c779a7a34cabe719fb99c3b2c Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 14:59:19 -0700 Subject: [PATCH 58/90] tor: Use privileged decorator for actions - Fixed issue with restarting start when apt transport is updated Tests: - Functional tests work - Initial setup works - 'plinth' instance is created - Enabling works - Firewall ports are updated. - Disabling works - Apt transport over Tor is disabled - Diagnostics work - Shows all ports for Tor - Updating configuration works - Correct value is set in configuration file - App page shows correct status - Setting/unsetting each of relay, bridge relay, bridges, hidden service, apt transport all work. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/tor/__init__.py | 26 +-- .../tor => plinth/modules/tor/privileged.py | 158 ++++++------------ plinth/modules/tor/utils.py | 11 +- plinth/modules/tor/views.py | 44 ++--- 4 files changed, 83 insertions(+), 156 deletions(-) rename actions/tor => plinth/modules/tor/privileged.py (76%) mode change 100755 => 100644 diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py index 279f7f8c7..cae907cde 100644 --- a/plinth/modules/tor/__init__.py +++ b/plinth/modules/tor/__init__.py @@ -1,13 +1,9 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Tor. -""" - -import json +"""FreedomBox app to configure Tor.""" from django.utils.translation import gettext_lazy as _ -from plinth import action_utils, actions +from plinth import action_utils from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import (Daemon, app_is_running, diagnose_netcat, @@ -21,7 +17,7 @@ from plinth.package import Packages from plinth.signals import domain_added, domain_removed from plinth.utils import format_lazy -from . import manifest, utils +from . import manifest, privileged, utils _description = [ _('Tor is an anonymous communication system. You can learn more ' @@ -109,13 +105,12 @@ class TorApp(app_module.App): def enable(self): """Enable the app and update firewall ports.""" super().enable() - actions.superuser_run('tor', ['update-ports']) + privileged.update_ports() update_hidden_service_domain() def disable(self): """Disable APT use of Tor before disabling.""" - actions.superuser_run('tor', - ['configure', '--apt-transport-tor', 'disable']) + privileged.configure(apt_transport_tor=False) super().disable() update_hidden_service_domain() @@ -125,8 +120,8 @@ class TorApp(app_module.App): results.extend(_diagnose_control_port()) - output = actions.superuser_run('tor', ['get-status']) - ports = json.loads(output)['ports'] + status = privileged.get_status() + ports = status['ports'] results.append([ _('Tor relay port available'), @@ -169,12 +164,9 @@ class TorApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('tor', - ['setup', '--old-version', - str(old_version)]) + privileged.setup(old_version) if not old_version: - actions.superuser_run( - 'tor', ['configure', '--apt-transport-tor', 'enable']) + privileged.configure(apt_transport_tor=True) update_hidden_service_domain() self.enable() diff --git a/actions/tor b/plinth/modules/tor/privileged.py old mode 100755 new mode 100644 similarity index 76% rename from actions/tor rename to plinth/modules/tor/privileged.py index 6189562f9..75b572001 --- a/actions/tor +++ b/plinth/modules/tor/privileged.py @@ -1,21 +1,18 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for the Tor service -""" +"""Configure Tor service.""" -import argparse import codecs -import json import os import re import socket import subprocess import time +from typing import Any, Optional, Union import augeas from plinth import action_utils +from plinth.actions import privileged from plinth.modules.tor.utils import (APT_TOR_PREFIX, get_augeas, get_real_apt_uri_path, iter_apt_uris) @@ -25,48 +22,10 @@ TOR_STATE_FILE = '/var/lib/tor-instances/plinth/state' TOR_AUTH_COOKIE = '/var/run/tor-instances/plinth/control.authcookie' -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - setup_parser = subparsers.add_parser('setup', - help='Setup Tor configuration') - setup_parser.add_argument( - '--old-version', type=int, required=True, - help='Version number being upgraded from or None if setting up first ' - 'time.') - - subparsers.add_parser('get-status', help='Get Tor status in JSON format') - - configure = subparsers.add_parser('configure', help='Configure Tor') - configure.add_argument('--relay', choices=['enable', 'disable'], - help='Configure relay') - configure.add_argument('--bridge-relay', choices=['enable', 'disable'], - help='Configure bridge relay') - configure.add_argument('--hidden-service', choices=['enable', 'disable'], - help='Configure hidden service') - configure.add_argument('--apt-transport-tor', - choices=['enable', 'disable'], - help='Configure package download over Tor') - configure.add_argument('--use-upstream-bridges', - choices=['enable', 'disable'], - help='Configure use of upstream bridges') - configure.add_argument('--upstream-bridges', - help='Set list of upstream bridges to use') - - subparsers.add_parser('update-ports', - help='Update firewall ports based on what Tor uses') - - subparsers.add_parser('restart', help='Restart Tor') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_setup(arguments): +@privileged +def setup(old_version: int): """Setup Tor configuration after installing it.""" - if arguments.old_version and arguments.old_version <= 4: + if old_version and old_version <= 4: _upgrade_orport_value() return @@ -98,7 +57,7 @@ def _first_time_setup(): aug.set(TOR_CONFIG + '/SocksPort[1]', '[::]:9050') aug.set(TOR_CONFIG + '/SocksPort[2]', '0.0.0.0:9050') aug.set(TOR_CONFIG + '/ControlPort', '9051') - _enable_relay(relay='enable', bridge='enable', aug=aug) + _enable_relay(relay=True, bridge=True, aug=aug) aug.set(TOR_CONFIG + '/ExitPolicy[1]', 'reject *:*') aug.set(TOR_CONFIG + '/ExitPolicy[2]', 'reject6 *:*') @@ -163,43 +122,46 @@ def _upgrade_orport_value(): action_utils.service_restart('firewalld') -def subcommand_get_status(_): - """Get Tor status in JSON format.""" - print(json.dumps(get_status())) - - -def subcommand_configure(arguments): +@privileged +def configure(use_upstream_bridges: Optional[bool] = None, + upstream_bridges: Optional[str] = None, + relay: Optional[bool] = None, + bridge_relay: Optional[bool] = None, + hidden_service: Optional[bool] = None, + apt_transport_tor: Optional[bool] = None): """Configure Tor.""" aug = augeas_load() - _use_upstream_bridges(arguments.use_upstream_bridges, aug=aug) + _use_upstream_bridges(use_upstream_bridges, aug=aug) - if arguments.use_upstream_bridges == 'enable': - arguments.relay = 'disable' - arguments.bridge_relay = 'disable' + if use_upstream_bridges: + relay = False + bridge_relay = False - if arguments.upstream_bridges: - _set_upstream_bridges(arguments.upstream_bridges, aug=aug) + if upstream_bridges: + _set_upstream_bridges(upstream_bridges, aug=aug) - _enable_relay(arguments.relay, arguments.bridge_relay, aug=aug) + _enable_relay(relay, bridge_relay, aug=aug) - if arguments.hidden_service == 'enable': + if hidden_service: _enable_hs(aug=aug) - elif arguments.hidden_service == 'disable': + elif hidden_service is not None: _disable_hs(aug=aug) - if arguments.apt_transport_tor == 'enable': + if apt_transport_tor: _enable_apt_transport_tor() - elif arguments.apt_transport_tor == 'disable': + elif apt_transport_tor is not None: _disable_apt_transport_tor() -def subcommand_update_ports(_): +@privileged +def update_ports(): """Update firewall ports based on what Tor uses.""" _update_ports() -def subcommand_restart(_): +@privileged +def restart(): """Restart Tor.""" if (action_utils.service_is_enabled('tor@plinth', strict_check=True) and action_utils.service_is_running('tor@plinth')): @@ -216,7 +178,8 @@ def subcommand_restart(_): time.sleep(10) -def get_status(): +@privileged +def get_status() -> dict[str, Union[bool, str, dict[str, Any]]]: """Return dict with Tor status.""" aug = augeas_load() return { @@ -229,32 +192,32 @@ def get_status(): } -def _are_upstream_bridges_enabled(aug): +def _are_upstream_bridges_enabled(aug) -> bool: """Return whether upstream bridges are being used.""" use_bridges = aug.get(TOR_CONFIG + '/UseBridges') return use_bridges == '1' -def _get_upstream_bridges(aug): +def _get_upstream_bridges(aug) -> str: """Return upstream bridges separated by newlines.""" matches = aug.match(TOR_CONFIG + '/Bridge') bridges = [aug.get(match) for match in matches] return '\n'.join(bridges) -def _is_relay_enabled(aug): +def _is_relay_enabled(aug) -> bool: """Return whether a relay is enabled.""" orport = aug.get(TOR_CONFIG + '/ORPort[1]') return bool(orport) and orport != '0' -def _is_bridge_relay_enabled(aug): +def _is_bridge_relay_enabled(aug) -> bool: """Return whether bridge relay is enabled.""" bridge = aug.get(TOR_CONFIG + '/BridgeRelay') return bridge == '1' -def _get_ports(): +def _get_ports() -> dict[str, str]: """Return dict mapping port names to numbers.""" ports = {} try: @@ -275,7 +238,7 @@ def _get_ports(): return ports -def _get_orport(): +def _get_orport() -> str: """Return the ORPort by querying running instance.""" cookie = open(TOR_AUTH_COOKIE, 'rb').read() cookie = codecs.encode(cookie, 'hex').decode() @@ -296,8 +259,8 @@ QUIT return matches.group(1) -def _get_hidden_service(aug=None): - """Return a string with configured Tor hidden service information""" +def _get_hidden_service(aug=None) -> dict[str, Any]: + """Return a string with configured Tor hidden service information.""" hs_enabled = False hs_status = 'Ok' hs_hostname = None @@ -344,7 +307,8 @@ def _disable(): action_utils.service_disable('tor@plinth') -def _use_upstream_bridges(use_upstream_bridges=None, aug=None): +def _use_upstream_bridges(use_upstream_bridges: Optional[bool] = None, + aug=None): """Enable use of upstream bridges.""" if use_upstream_bridges is None: return @@ -352,9 +316,9 @@ def _use_upstream_bridges(use_upstream_bridges=None, aug=None): if not aug: aug = augeas_load() - if use_upstream_bridges == 'enable': + if use_upstream_bridges: aug.set(TOR_CONFIG + '/UseBridges', '1') - elif use_upstream_bridges == 'disable': + else: aug.set(TOR_CONFIG + '/UseBridges', '0') aug.save() @@ -383,7 +347,8 @@ def _set_upstream_bridges(upstream_bridges=None, aug=None): aug.save() -def _enable_relay(relay=None, bridge=None, aug=None): +def _enable_relay(relay: Optional[bool], bridge: Optional[bool], + aug: augeas.Augeas): """Enable Tor bridge relay.""" if relay is None and bridge is None: return @@ -393,18 +358,18 @@ def _enable_relay(relay=None, bridge=None, aug=None): use_upstream_bridges = _are_upstream_bridges_enabled(aug) - if relay == 'enable' and not use_upstream_bridges: + if relay and not use_upstream_bridges: aug.set(TOR_CONFIG + '/ORPort[1]', '9001') aug.set(TOR_CONFIG + '/ORPort[2]', '[::]:9001') - elif relay == 'disable': + elif relay is not None: aug.remove(TOR_CONFIG + '/ORPort') - if bridge == 'enable' and not use_upstream_bridges: + if bridge and not use_upstream_bridges: aug.set(TOR_CONFIG + '/BridgeRelay', '1') aug.set(TOR_CONFIG + '/ServerTransportPlugin', 'obfs3,obfs4 exec /usr/bin/obfs4proxy') aug.set(TOR_CONFIG + '/ExtORPort', 'auto') - elif bridge == 'disable': + elif bridge is not None: aug.remove(TOR_CONFIG + '/BridgeRelay') aug.remove(TOR_CONFIG + '/ServerTransportPlugin') aug.remove(TOR_CONFIG + '/ExtORPort') @@ -413,7 +378,7 @@ def _enable_relay(relay=None, bridge=None, aug=None): def _enable_hs(aug=None): - """Enable Tor hidden service""" + """Enable Tor hidden service.""" if not aug: aug = augeas_load() @@ -429,7 +394,7 @@ def _enable_hs(aug=None): def _disable_hs(aug=None): - """Disable Tor hidden service""" + """Disable Tor hidden service.""" if not aug: aug = augeas_load() @@ -443,13 +408,7 @@ def _disable_hs(aug=None): def _enable_apt_transport_tor(): """Enable package download over Tor.""" - try: - aug = get_augeas() - except Exception: - # If there was an error, don't proceed - print('Error: Unable to understand sources format.') - exit(1) - + aug = get_augeas() for uri_path in iter_apt_uris(aug): uri_path = get_real_apt_uri_path(aug, uri_path) uri = aug.get(uri_path) @@ -527,16 +486,3 @@ def augeas_load(): '/etc/tor/instances/plinth/torrc') aug.load() return aug - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/tor/utils.py b/plinth/modules/tor/utils.py index 935e48a85..8dba7d8da 100644 --- a/plinth/modules/tor/utils.py +++ b/plinth/modules/tor/utils.py @@ -1,19 +1,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Tor utility functions -""" +"""Tor utility functions.""" import glob import itertools -import json import augeas -from plinth import actions from plinth import app as app_module from plinth.daemon import app_is_running from plinth.modules.names.components import DomainName +from . import privileged + APT_SOURCES_URI_PATHS = ('/files/etc/apt/sources.list/*/uri', '/files/etc/apt/sources.list.d/*/*/uri') APT_TOR_PREFIX = 'tor+' @@ -21,8 +19,7 @@ APT_TOR_PREFIX = 'tor+' def get_status(initialized=True): """Return current Tor status.""" - output = actions.superuser_run('tor', ['get-status']) - status = json.loads(output) + status = privileged.get_status() hs_info = status['hidden_service'] hs_services = [] diff --git a/plinth/modules/tor/views.py b/plinth/modules/tor/views.py index 135a6f01b..9d7c3d4ab 100644 --- a/plinth/modules/tor/views.py +++ b/plinth/modules/tor/views.py @@ -1,19 +1,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring Tor. -""" +"""FreedomBox app for configuring Tor.""" import logging from django.utils.translation import gettext_noop from django.views.generic.edit import FormView -from plinth import actions from plinth import app as app_module from plinth import operation as operation_module from plinth.modules import tor from plinth.views import AppView +from . import privileged from . import utils as tor_utils from .forms import TorForm @@ -81,49 +79,43 @@ def _apply_changes(old_status, new_status): def __apply_changes(old_status, new_status): """Apply the changes.""" - needs_restart = True - arguments = [] + needs_restart = False + arguments = {} app = app_module.App.get('tor') is_enabled = app.is_enabled() if old_status['relay_enabled'] != new_status['relay_enabled']: - arg_value = 'enable' if new_status['relay_enabled'] else 'disable' - arguments.extend(['--relay', arg_value]) + arguments['relay'] = new_status['relay_enabled'] + needs_restart = True if old_status['bridge_relay_enabled'] != \ new_status['bridge_relay_enabled']: - arg_value = 'enable' - if not new_status['bridge_relay_enabled']: - arg_value = 'disable' - arguments.extend(['--bridge-relay', arg_value]) + arguments['bridge_relay'] = new_status['bridge_relay_enabled'] + needs_restart = True if old_status['hs_enabled'] != new_status['hs_enabled']: - arg_value = 'enable' if new_status['hs_enabled'] else 'disable' - arguments.extend(['--hidden-service', arg_value]) + arguments['hidden_service'] = new_status['hs_enabled'] + needs_restart = True if old_status['apt_transport_tor_enabled'] != \ new_status['apt_transport_tor_enabled']: - arg_value = 'disable' - if is_enabled and new_status['apt_transport_tor_enabled']: - arg_value = 'enable' - arguments.extend(['--apt-transport-tor', arg_value]) - needs_restart = False + arguments['apt_transport_tor'] = ( + is_enabled and new_status['apt_transport_tor_enabled']) if old_status['use_upstream_bridges'] != \ new_status['use_upstream_bridges']: - arg_value = 'enable' if new_status[ - 'use_upstream_bridges'] else 'disable' - arguments.extend(['--use-upstream-bridges', arg_value]) + arguments['use_upstream_bridges'] = new_status['use_upstream_bridges'] + needs_restart = True if old_status['upstream_bridges'] != new_status['upstream_bridges']: - arguments.extend( - ['--upstream-bridges', new_status['upstream_bridges']]) + arguments['upstream_bridges'] = new_status['upstream_bridges'] + needs_restart = True if arguments: - actions.superuser_run('tor', ['configure'] + arguments) + privileged.configure(**arguments) if needs_restart and is_enabled: - actions.superuser_run('tor', ['restart']) + privileged.restart() status = tor_utils.get_status() tor.update_hidden_service_domain(status) From 623bcefe2216ec3814c7ba494ada36152ddff744 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 16 Sep 2022 10:52:02 -0700 Subject: [PATCH 59/90] transmission: Minor update to privileged method signature Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/transmission/privileged.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plinth/modules/transmission/privileged.py b/plinth/modules/transmission/privileged.py index 3daceed37..b9fe96483 100644 --- a/plinth/modules/transmission/privileged.py +++ b/plinth/modules/transmission/privileged.py @@ -20,7 +20,7 @@ def get_configuration() -> dict[str, str]: @privileged -def merge_configuration(configuration: dict[str, Union[str, bool]]) -> None: +def merge_configuration(configuration: dict[str, Union[str, bool]]): """Merge given JSON configuration with existing configuration.""" current_configuration = _transmission_config.read_bytes() current_configuration = json.loads(current_configuration) From 11a27d8efc5295abac8f00a51297a3845b129b13 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 15:07:32 -0700 Subject: [PATCH 60/90] ttrss: Use privileged decorator for actions Tests: - Ignore setting a None domain - Updated tests to use base class - Functional tests work - Backup/restore works. Database is dumped and restored. - Initial setup works - Enabling/disabling works - API access is enabled and a valid domain is set when available - Setting the domain works - Configuration is updated in update.php - App page show newly set domain - Not tested: force upgrade of package Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/ttrss/__init__.py | 36 +++------ .../modules/ttrss/privileged.py | 74 ++++++------------- plinth/modules/ttrss/tests/test_functional.py | 43 ++++------- plinth/modules/ttrss/views.py | 13 +++- plinth/tests/functional/__init__.py | 1 + 5 files changed, 60 insertions(+), 107 deletions(-) rename actions/ttrss => plinth/modules/ttrss/privileged.py (69%) mode change 100755 => 100644 diff --git a/plinth/modules/ttrss/__init__.py b/plinth/modules/ttrss/__init__.py index fc2fb9efa..d8ad1b026 100644 --- a/plinth/modules/ttrss/__init__.py +++ b/plinth/modules/ttrss/__init__.py @@ -1,12 +1,9 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Tiny Tiny RSS. -""" +"""FreedomBox app to configure Tiny Tiny RSS.""" from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -17,7 +14,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages, install from plinth.utils import Version, format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, ' @@ -97,20 +94,20 @@ class TTRSSApp(app_module.App): def enable(self): """Enable components and API access.""" super().enable() - actions.superuser_run('ttrss', ['enable-api-access']) + privileged.enable_api_access() # Try to set the domain to one of the available TLS domains - domain = get_domain() + domain = privileged.get_domain() if not domain or domain == 'localhost': from plinth.modules import names domain = next(names.get_available_tls_domains(), None) - set_domain(domain) + privileged.set_domain(domain) def setup(self, old_version): """Install and configure the app.""" - actions.superuser_run('ttrss', ['pre-setup']) + privileged.pre_setup() super().setup(old_version) - actions.superuser_run('ttrss', ['setup']) + privileged.setup() self.enable() def force_upgrade(self, packages): @@ -124,30 +121,19 @@ class TTRSSApp(app_module.App): return False install(['tt-rss'], force_configuration='new') - actions.superuser_run('ttrss', ['setup']) + privileged.setup() return True class TTRSSBackupRestore(BackupRestore): - """Component to backup/restore TT-RSS""" + """Component to backup/restore TT-RSS.""" def backup_pre(self, packet): """Save database contents.""" super().backup_pre(packet) - actions.superuser_run('ttrss', ['dump-database']) + privileged.dump_database() def restore_post(self, packet): """Restore database contents.""" super().restore_post(packet) - actions.superuser_run('ttrss', ['restore-database']) - - -def get_domain(): - """Read TLS domain from tt-rss config file.""" - return actions.superuser_run('ttrss', ['get-domain']).strip() - - -def set_domain(domain): - """Set the TLS domain in tt-rss configuration file.""" - if domain: - actions.superuser_run('ttrss', ['set-domain', domain]) + privileged.restore_database() diff --git a/actions/ttrss b/plinth/modules/ttrss/privileged.py old mode 100755 new mode 100644 similarity index 69% rename from actions/ttrss rename to plinth/modules/ttrss/privileged.py index 3ae8caffb..dcc242ef4 --- a/actions/ttrss +++ b/plinth/modules/ttrss/privileged.py @@ -1,16 +1,14 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Tiny Tiny RSS. -""" +"""Configure Tiny Tiny RSS.""" -import argparse import os import subprocess +from typing import Optional import augeas from plinth import action_utils +from plinth.actions import privileged CONFIG_FILE = '/etc/tt-rss/config.php' DEFAULT_FILE = '/etc/default/tt-rss' @@ -18,36 +16,15 @@ DATABASE_FILE = '/etc/tt-rss/database.php' DB_BACKUP_FILE = '/var/lib/plinth/backups-data/ttrss-database.sql' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('pre-setup', help='Perform pre-setup operations') - subparsers.add_parser('setup', help='Setup Tiny Tiny RSS configuration') - subparsers.add_parser('enable-api-access', help='Enable Tiny Tiny RSS API') - subparsers.add_parser('dump-database', help='Dump database to file') - subparsers.add_parser('restore-database', - help='Restore database from file') - subparsers.add_parser('get-domain', - help='Get the domain set for Tiny Tiny RSS.') - set_domain = subparsers.add_parser( - 'set-domain', help='Set the domain to be used by Tiny Tiny RSS.') - set_domain.add_argument( - 'domain_name', - help='The domain name that will be used by Tiny Tiny RSS.') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_pre_setup(_): +@privileged +def pre_setup(): """Preseed debconf values before packages are installed.""" action_utils.debconf_set_selections( ['tt-rss tt-rss/database-type string pgsql']) -def subcommand_get_domain(_): +@privileged +def get_domain() -> Optional[str]: """Get the domain set for Tiny Tiny RSS.""" aug = load_augeas() @@ -55,12 +32,18 @@ def subcommand_get_domain(_): for match in aug.match('/files' + CONFIG_FILE + '/define'): if aug.get(match) == 'SELF_URL_PATH': url = aug.get(match + '/value').strip("'") - print(urlparse(url).netloc) + return urlparse(url).netloc + + return None -def subcommand_set_domain(args): +@privileged +def set_domain(domain_name: Optional[str]): """Set the domain to be used by Tiny Tiny RSS.""" - url = f"'https://{args.domain_name}/tt-rss/'" + if not domain_name: + return + + url = f"'https://{domain_name}/tt-rss/'" aug = load_augeas() for match in aug.match('/files' + CONFIG_FILE + '/define'): @@ -70,7 +53,8 @@ def subcommand_set_domain(args): aug.save() -def subcommand_setup(_): +@privileged +def setup(): """Setup Tiny Tiny RSS configuration.""" aug = load_augeas() @@ -96,7 +80,8 @@ def subcommand_setup(_): action_utils.service_restart('tt-rss') -def subcommand_enable_api_access(_): +@privileged +def enable_api_access(): """Enable API access so that tt-rss can be accessed through mobile app.""" import psycopg2 # Only available post installation @@ -123,14 +108,16 @@ def subcommand_enable_api_access(_): connection.close() -def subcommand_dump_database(_): +@privileged +def dump_database(): """Dump database to file.""" os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True) with open(DB_BACKUP_FILE, 'w', encoding='utf-8') as db_backup_file: _run_as_postgres(['pg_dump', 'ttrss'], stdout=db_backup_file) -def subcommand_restore_database(_): +@privileged +def restore_database(): """Restore database from file.""" _run_as_postgres(['dropdb', 'ttrss']) _run_as_postgres(['createdb', 'ttrss']) @@ -155,16 +142,3 @@ def load_augeas(): aug.set('/augeas/load/Phpvars/incl[last() + 1]', DATABASE_FILE) aug.load() return aug - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/ttrss/tests/test_functional.py b/plinth/modules/ttrss/tests/test_functional.py index b47202b6e..8ca0d62ef 100644 --- a/plinth/modules/ttrss/tests/test_functional.py +++ b/plinth/modules/ttrss/tests/test_functional.py @@ -12,38 +12,25 @@ APP_ID = 'ttrss' pytestmark = [pytest.mark.apps, pytest.mark.ttrss, pytest.mark.sso] -@pytest.fixture(scope='module', autouse=True) -def fixture_background(session_browser): - """Login and install the app.""" - functional.login(session_browser) - functional.install(session_browser, APP_ID) - yield - functional.app_disable(session_browser, APP_ID) +class TestTTRSSApp(functional.BaseAppTests): + """Class to customize basic app tests for TTRSS.""" + app_name = 'ttrss' + has_service = True + has_web = True -def test_enable_disable(session_browser): - """Test enabling the app.""" - functional.app_disable(session_browser, APP_ID) + @pytest.mark.backups + def test_backup_restore(self, session_browser): + """Test backup and restore of app data.""" + functional.app_enable(session_browser, APP_ID) + _subscribe(session_browser) + functional.backup_create(session_browser, APP_ID, 'test_ttrss') - functional.app_enable(session_browser, APP_ID) - assert functional.service_is_running(session_browser, APP_ID) + _unsubscribe(session_browser) + functional.backup_restore(session_browser, APP_ID, 'test_ttrss') - functional.app_disable(session_browser, APP_ID) - assert functional.service_is_not_running(session_browser, APP_ID) - - -@pytest.mark.backups -def test_backup_restore(session_browser): - """Test backup and restore of app data.""" - functional.app_enable(session_browser, APP_ID) - _subscribe(session_browser) - functional.backup_create(session_browser, APP_ID, 'test_ttrss') - - _unsubscribe(session_browser) - functional.backup_restore(session_browser, APP_ID, 'test_ttrss') - - assert functional.service_is_running(session_browser, APP_ID) - assert _is_subscribed(session_browser) + assert functional.service_is_running(session_browser, APP_ID) + assert _is_subscribed(session_browser) def _ttrss_load_main_interface(browser): diff --git a/plinth/modules/ttrss/views.py b/plinth/modules/ttrss/views.py index c71be5ae0..244aa462e 100644 --- a/plinth/modules/ttrss/views.py +++ b/plinth/modules/ttrss/views.py @@ -1,28 +1,33 @@ # SPDX-License-Identifier: AGPL-3.0-or-later +"""Django views for Tiny Tiny RSS app.""" from django.contrib import messages from django.utils.translation import gettext_lazy as _ from plinth.forms import TLSDomainForm -from plinth.modules import ttrss from plinth.views import AppView +from . import privileged + class TTRSSAppView(AppView): + """Show TTRSS app main view.""" + app_id = 'ttrss' form_class = TLSDomainForm def get_initial(self): """Return the values to fill in the form.""" initial = super().get_initial() - initial['domain'] = ttrss.get_domain() + initial['domain'] = privileged.get_domain() return initial def form_valid(self, form): """Change the domain of TT-RSS app.""" data = form.cleaned_data - if ttrss.get_domain() != data['domain']: - ttrss.set_domain(data['domain']) + old_data = form.initial + if old_data['domain'] != data['domain']: + privileged.set_domain(data['domain']) messages.success(self.request, _('Configuration updated')) return super().form_valid(form) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index 2d2660fe6..1af83bc06 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -44,6 +44,7 @@ _site_url = { 'cockpit': '/_cockpit/', 'syncthing': '/syncthing/', 'rssbridge': '/rss-bridge/', + 'ttrss': '/tt-rss/', } _sys_modules = [ From 66c1ddc40426863dcf1cd18f7348a0a3ecf25748 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 07:31:31 -0700 Subject: [PATCH 61/90] upgrades: Use privileged decorator for actions Tests: - DONE: Functional tests work - DONE: Initial setup works - DONE: Automatic upgrades are enable by default - DONE: apt preferences have been updated - DONE: Enabling backports works - DONE: Configuration file is created - DONE: Correct status is shown in the app page - DONE: Enabling/disabling automatic upgrades works - DONE: Configuration file is updated - DONE: Correct status is shown in the app page - DONE: Manual triggering of updates work - DONE: Log is shown properly in the app page - DONE: Checking for distribution upgrade works - DONE: Distribution upgrade from stable to testing works - DONE: When running on btrfs distribution, snapshot is created before. - DONE: Snapshots will be disable before upgrade and re-enabled later. - DONE: When searx is enabled before upgrade, it's uwsgi will be disabled and re-enabled later. - Failures due to freedombox package not being the latest version (with the changes). - DONE: Development Vagrant box - DONE: Automatic updates are disabled during development setup - DONE: Development Container - DONE: Automatic updates are disabled during development setup - DONE: On stable, backports are enabled when running tests Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- Vagrantfile | 2 +- container | 7 +- plinth/modules/upgrades/__init__.py | 46 +--- .../modules/upgrades/privileged.py | 196 +++++++----------- plinth/modules/upgrades/views.py | 40 ++-- 5 files changed, 110 insertions(+), 181 deletions(-) rename actions/upgrades => plinth/modules/upgrades/privileged.py (78%) mode change 100755 => 100644 diff --git a/Vagrantfile b/Vagrantfile index e7566016e..3d518b5f0 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -16,7 +16,7 @@ Vagrant.configure(2) do |config| end config.vm.provision "shell", run: 'always', inline: <<-SHELL # Disable automatic upgrades - /vagrant/actions/upgrades disable-auto + echo -e 'APT::Periodic::Update-Package-Lists "0";\nAPT::Periodic::Unattended-Upgrade "0";' > //etc/apt/apt.conf.d/20auto-upgrades # Do not run system plinth systemctl stop plinth systemctl disable plinth diff --git a/container b/container index 7884a2913..bf031ca8f 100755 --- a/container +++ b/container @@ -193,7 +193,7 @@ mount -o remount /freedombox if [[ "{distribution}" == "stable" && ! -e $BACKPORTS_SOURCES_LIST ]] then echo "> In container: Enable backports" - /freedombox/actions/upgrades activate-backports + /freedombox/actions/actions upgrades activate_backports --no-args fi echo "> In container: Upgrade packages" @@ -698,7 +698,10 @@ def _setup(image_file, distribution): return logger.info('In container: Disabling automatic updates temporarily') - _runc(image_file, ['/usr/share/plinth/actions/upgrades', 'disable-auto']) + contents = 'APT::Periodic::Update-Package-Lists "0";\n' \ + 'APT::Periodic::Unattended-Upgrade "0";\n' + _runc(image_file, ['tee', '/etc/apt/apt.conf.d/20auto-upgrades'], + input=contents.encode()) logger.info('In container: Disabling FreedomBox service') _runc(image_file, ['systemctl', 'disable', 'plinth'], diff --git a/plinth/modules/upgrades/__init__.py b/plinth/modules/upgrades/__init__.py index a530f868e..4a732df83 100644 --- a/plinth/modules/upgrades/__init__.py +++ b/plinth/modules/upgrades/__init__.py @@ -1,9 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for upgrades. -""" +"""FreedomBox app for upgrades.""" -import json import logging import os import subprocess @@ -13,14 +10,13 @@ from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_noop import plinth -from plinth import actions from plinth import app as app_module from plinth import cfg, glib, kvstore, menu from plinth.daemon import RelatedDaemon from plinth.modules.backups.components import BackupRestore from plinth.package import Packages -from . import manifest +from . import manifest, privileged first_boot_steps = [ { @@ -48,10 +44,6 @@ BACKPORTS_REQUESTED_KEY = 'upgrades_backports_requested' DIST_UPGRADE_ENABLED_KEY = 'upgrades_dist_upgrade_enabled' -SOURCES_LIST = '/etc/apt/sources.list' - -BACKPORTS_SOURCES_LIST = '/etc/apt/sources.list.d/freedombox2.list' - logger = logging.getLogger(__name__) @@ -140,11 +132,11 @@ class UpgradesApp(app_module.App): # Enable automatic upgrades but only on first install if not old_version and not cfg.develop: - actions.superuser_run('upgrades', ['enable-auto']) + privileged.enable_auto() # Update apt preferences whenever on first install and on version # increment. - actions.superuser_run('upgrades', ['setup']) + privileged.setup() # When upgrading from a version without first boot wizard for # backports, assume backports have been requested. @@ -161,30 +153,10 @@ class UpgradesApp(app_module.App): setup_repositories(None) -def is_enabled(): - """Return whether the module is enabled.""" - output = actions.run('upgrades', ['check-auto']) - return 'True' in output.split() - - -def enable(): - """Enable the module.""" - actions.superuser_run('upgrades', ['enable-auto']) - - -def disable(): - """Disable the module.""" - actions.superuser_run('upgrades', ['disable-auto']) - - def setup_repositories(_): """Setup apt repositories for backports.""" if is_backports_requested(): - command = ['activate-backports'] - if cfg.develop: - command.append('--develop') - - actions.superuser_run('upgrades', command) + privileged.activate_backports(cfg.develop) def check_dist_upgrade(_): @@ -196,12 +168,8 @@ def check_dist_upgrade(_): def try_start_dist_upgrade(test=False): """Try to start dist upgrade.""" from plinth.notification import Notification - command = ['start-dist-upgrade'] - if test: - command.append('--test') - output = actions.superuser_run('upgrades', command) - result = json.loads(output) + result = privileged.start_dist_upgrade(test) dist_upgrade_started = result['dist_upgrade_started'] reason = result['reason'] if 'found-previous' in reason: @@ -270,7 +238,7 @@ def set_dist_upgrade_enabled(enabled=True): def is_backports_enabled(): """Return whether backports are enabled in the system configuration.""" - return os.path.exists(BACKPORTS_SOURCES_LIST) + return os.path.exists(privileged.BACKPORTS_SOURCES_LIST) def get_current_release(): diff --git a/actions/upgrades b/plinth/modules/upgrades/privileged.py old mode 100755 new mode 100644 similarity index 78% rename from actions/upgrades rename to plinth/modules/upgrades/privileged.py index d5e7960f8..43a2c2ea3 --- a/actions/upgrades +++ b/plinth/modules/upgrades/privileged.py @@ -1,30 +1,26 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configures or runs unattended-upgrades -""" +"""Configure or run unattended-upgrades.""" -import argparse -import json import logging import os import pathlib import re import subprocess -import sys import time -from typing import List, Tuple +from typing import List, Tuple, Union from plinth.action_utils import (apt_hold, apt_hold_flag, apt_hold_freedombox, apt_unhold_freedombox, debconf_set_selections, is_package_manager_busy, run_apt_command, service_daemon_reload, service_restart) +from plinth.actions import privileged from plinth.modules.apache.components import check_url from plinth.modules.snapshot import is_apt_snapshots_enabled from plinth.modules.snapshot import is_supported as snapshot_is_supported from plinth.modules.snapshot import load_augeas as snapshot_load_augeas -from plinth.modules.upgrades import (BACKPORTS_SOURCES_LIST, SOURCES_LIST, - get_current_release, is_backports_current) + +SOURCES_LIST = '/etc/apt/sources.list' +BACKPORTS_SOURCES_LIST = '/etc/apt/sources.list.d/freedombox2.list' AUTO_CONF_FILE = '/etc/apt/apt.conf.d/20auto-upgrades' LOG_FILE = '/var/log/unattended-upgrades/unattended-upgrades.log' @@ -32,7 +28,8 @@ DPKG_LOG_FILE = '/var/log/unattended-upgrades/unattended-upgrades-dpkg.log' RELEASE_FILE_URL = \ 'https://deb.debian.org/debian/dists/{}/Release' -APT_PREFERENCES_FREEDOMBOX = '''Explanation: This file is managed by FreedomBox, do not edit. +APT_PREFERENCES_FREEDOMBOX = \ + '''Explanation: This file is managed by FreedomBox, do not edit. Explanation: Allow carefully selected updates to 'freedombox' from backports. Package: src:freedombox Pin: release a={}-backports @@ -42,7 +39,8 @@ Pin-Priority: 500 # Whenever these preferences needs to change, increment the version number # upgrades app. This ensures that setup is run again and the new contents are # overwritten on the old file. -APT_PREFERENCES_APPS = '''Explanation: This file is managed by FreedomBox, do not edit. +APT_PREFERENCES_APPS = \ + '''Explanation: This file is managed by FreedomBox, do not edit. Explanation: matrix-synapse shall not be available in Debian stable but Explanation: only in backports. Upgrade priority of packages that have needed Explanation: versions only in backports. @@ -104,7 +102,7 @@ Description=Upgrade to new stable Debian release [Service] Type=oneshot -ExecStart=/usr/share/plinth/actions/upgrades dist-upgrade +ExecStart=/usr/share/plinth/actions/actions upgrades dist_upgrade --no-args KillMode=process TimeoutSec=12hr ''' @@ -116,46 +114,18 @@ dist_upgrade_flag = pathlib.Path( '/var/lib/freedombox/dist-upgrade-in-progress') -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('run', help='Upgrade packages on the system') - subparsers.add_parser('check-auto', - help='Check if automatic upgrades are enabled') - subparsers.add_parser('enable-auto', help='Enable automatic upgrades') - subparsers.add_parser('disable-auto', help='Disable automatic upgrades.') - subparsers.add_parser('get-log', help='Print the automatic upgrades log') - - subparsers.add_parser('setup', help='Setup apt preferences') - - activate_backports = subparsers.add_parser( - 'activate-backports', help='Activate backports if possible') - activate_backports.add_argument('--develop', required=False, default=False, - action='store_true', - help='Development mode') - - start_dist_upgrade = subparsers.add_parser( - 'start-dist-upgrade', help='Check and start dist upgrade process') - start_dist_upgrade.add_argument( - '--test', required=False, default=False, action='store_true', - help='Test dist-upgrade from stable to testing') - subparsers.add_parser('dist-upgrade', help='Perform dist upgrade') - - subparsers.required = True - return parser.parse_args() - - def _release_held_freedombox(): - """In case freedombox package was left in held state by an interrupted - process, release it.""" + """If freedombox package was left in held state, release it. + + This can happen due to an interrupted process. + """ if apt_hold_flag.exists() and not is_package_manager_busy(): apt_unhold_freedombox() -def _run(): - """Run unattended-upgrades""" +@privileged +def run(): + """Run unattended-upgrades.""" subprocess.run(['dpkg', '--configure', '-a'], check=False) run_apt_command(['--fix-broken', 'install']) _release_held_freedombox() @@ -166,18 +136,6 @@ def _run(): start_new_session=True) -def subcommand_run(_): - """Run unattended-upgrades""" - try: - _run() - except FileNotFoundError: - print('Error: systemctl is not available.', file=sys.stderr) - sys.exit(2) - except Exception as error: - print('Error: {0}'.format(error), file=sys.stderr) - sys.exit(3) - - def _check_auto() -> bool: """Check if automatic upgrades are enabled.""" arguments = [ @@ -193,45 +151,48 @@ def _check_auto() -> bool: return bool(update_interval) -def subcommand_check_auto(_): - """Check if automatic upgrades are enabled""" - try: - print(_check_auto()) - except subprocess.CalledProcessError as error: - print('Error: {0}'.format(error), file=sys.stderr) - sys.exit(1) +@privileged +def check_auto() -> bool: + """Check if automatic upgrades are enabled.""" + return _check_auto() -def subcommand_enable_auto(_): - """Enable automatic upgrades""" +@privileged +def enable_auto(): + """Enable automatic upgrades.""" with open(AUTO_CONF_FILE, 'w', encoding='utf-8') as conffile: conffile.write('APT::Periodic::Update-Package-Lists "1";\n') conffile.write('APT::Periodic::Unattended-Upgrade "1";\n') -def subcommand_disable_auto(_): - """Disable automatic upgrades""" +@privileged +def disable_auto(): + """Disable automatic upgrades.""" with open(AUTO_CONF_FILE, 'w', encoding='utf-8') as conffile: conffile.write('APT::Periodic::Update-Package-Lists "0";\n') conffile.write('APT::Periodic::Unattended-Upgrade "0";\n') -def subcommand_get_log(_): - """Print the automatic upgrades log.""" +@privileged +def get_log() -> str: + """Return the automatic upgrades log.""" + log_lines = [] try: - print('==> ' + os.path.basename(LOG_FILE)) + log_lines.append('==> ' + os.path.basename(LOG_FILE)) with open(LOG_FILE, 'r', encoding='utf-8') as file_handle: - print(file_handle.read()) + log_lines.append(file_handle.read()) except IOError: pass try: - print('==> ' + os.path.basename(DPKG_LOG_FILE)) + log_lines.append('==> ' + os.path.basename(DPKG_LOG_FILE)) with open(DPKG_LOG_FILE, 'r', encoding='utf-8') as file_handle: - print(file_handle.read()) + log_lines.append(file_handle.read()) except IOError: pass + return '\n'.join(log_lines) + def _get_protocol() -> str: """Return the protocol to use for newly added repository sources.""" @@ -278,8 +239,10 @@ def _check_and_backports_sources(develop=False): if os.path.exists(old_sources_list): os.remove(old_sources_list) + from plinth.modules.upgrades import (get_current_release, + is_backports_current) if is_backports_current(): - print('Repositories list up-to-date. Skipping update.') + logging.info('Repositories list up-to-date. Skipping update.') return try: @@ -290,25 +253,26 @@ def _check_and_backports_sources(develop=False): for line in default_origin.readlines() ] except FileNotFoundError: - print('Could not open /etc/dpkg/origins/default') + logging.info('Could not open /etc/dpkg/origins/default') return if not any(matches): - print('System is running a derivative of Debian. Skip enabling ' - 'backports.') + logging.info('System is running a derivative of Debian. Skip enabling ' + 'backports.') return release, dist = get_current_release() if release == 'unstable' or (release == 'testing' and not develop): - print(f'System release is {release}. Skip enabling backports.') + logging.info(f'System release is {release}. Skip enabling backports.') return protocol = _get_protocol() if protocol == 'tor+http': - print('Package download over Tor is enabled.') + logging.info('Package download over Tor is enabled.') if not _is_release_file_available(protocol, dist, backports=True): - print(f'Release file for {dist}-backports is not available yet.') + logging.info( + f'Release file for {dist}-backports is not available yet.') return print(f'{dist}-backports is now available. Adding to sources.') @@ -328,12 +292,14 @@ def _add_apt_preferences(): # Don't try to remove 50freedombox3.pref as this file is shipped with the # Debian package and is removed using maintainer scripts. + from plinth.modules.upgrades import get_current_release _, dist = get_current_release() if dist == 'sid': - print(f'System distribution is {dist}. Skip setting apt preferences ' - 'for backports.') + logging.info( + f'System distribution is {dist}. Skip setting apt preferences ' + 'for backports.') else: - print(f'Setting apt preferences for {dist}-backports.') + logging.info(f'Setting apt preferences for {dist}-backports.') with open(base_path / '50freedombox4.pref', 'w', encoding='utf-8') as file_handle: file_handle.write(APT_PREFERENCES_FREEDOMBOX.format(dist)) @@ -350,17 +316,20 @@ def _is_sufficient_free_space() -> bool: def _check_dist_upgrade(test_upgrade=False) -> Tuple[bool, str]: - """Check for new stable release, if updates are enabled, and if there is + """Check if a distribution upgrade be performed. + + Check for new stable release, if updates are enabled, and if there is enough free space for the dist upgrade. If test_upgrade is True, also check for upgrade to testing. - Returns (boolean, string) indicating if the upgrade is ready, and a reason + Return (boolean, string) indicating if the upgrade is ready, and a reason if not. """ if dist_upgrade_flag.exists(): return (True, 'found-previous') + from plinth.modules.upgrades import get_current_release release, dist = get_current_release() if release in ['unstable', 'testing']: return (False, f'already-{release}') @@ -429,7 +398,8 @@ def _check_dist_upgrade(test_upgrade=False) -> Tuple[bool, str]: def _take_snapshot_and_disable() -> bool: """Take a snapshot if supported and enabled, then disable snapshots. - Return whether snapshots shall be re-enabled at the end.""" + Return whether snapshots shall be re-enabled at the end. + """ if snapshot_is_supported(): print('Taking a snapshot before dist upgrade...', flush=True) subprocess.run([ @@ -467,7 +437,8 @@ def _restore_snapshots_config(reenable=False): def _disable_searx() -> bool: """If searx is enabled, disable it until we can upgrade it properly. - Return whether searx was originally enabled.""" + Return whether searx was originally enabled. + """ searx_is_enabled = pathlib.Path( '/etc/uwsgi/apps-enabled/searx.ini').exists() if searx_is_enabled: @@ -481,7 +452,9 @@ def _disable_searx() -> bool: def _update_searx(reenable=False): """If searx is installed, update search engines list. - Re-enable if previously enabled.""" + + Re-enable if previously enabled. + """ if pathlib.Path('/etc/searx/settings.yml').exists(): print('Updating searx search engines list...', flush=True) subprocess.run([ @@ -567,19 +540,20 @@ def _perform_dist_upgrade(): dist_upgrade_flag.unlink() -def subcommand_setup(_): +@privileged +def setup(): """Setup apt preferences.""" _add_apt_preferences() -def subcommand_activate_backports(arguments): +@privileged +def activate_backports(develop: bool = False): """Setup software repositories needed for FreedomBox. Repositories list for now only contains the backports. If the file exists, assume that it contains backports. - """ - _check_and_backports_sources(arguments.develop) + _check_and_backports_sources(develop) def _start_dist_upgrade_service(): @@ -595,7 +569,8 @@ def _start_dist_upgrade_service(): start_new_session=True) -def subcommand_start_dist_upgrade(arguments): +@privileged +def start_dist_upgrade(test: bool = False) -> dict[str, Union[str, bool]]: """Start dist upgrade process. Check if a new stable release is available, and start dist-upgrade process @@ -603,31 +578,14 @@ def subcommand_start_dist_upgrade(arguments): """ _release_held_freedombox() - upgrade_ready, reason = _check_dist_upgrade(arguments.test) + upgrade_ready, reason = _check_dist_upgrade(test) if upgrade_ready: _start_dist_upgrade_service() - print( - json.dumps({ - 'dist_upgrade_started': upgrade_ready, - 'reason': reason, - })) + return {'dist_upgrade_started': upgrade_ready, 'reason': reason} -def subcommand_dist_upgrade(_): - """Perform major distribution upgrade. - """ +@privileged +def dist_upgrade(): + """Perform major distribution upgrade.""" _perform_dist_upgrade() - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/upgrades/views.py b/plinth/modules/upgrades/views.py index 7d5e6cd23..98700f3de 100644 --- a/plinth/modules/upgrades/views.py +++ b/plinth/modules/upgrades/views.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for upgrades. -""" +"""FreedomBox app for upgrades.""" + import subprocess from apt.cache import Cache @@ -13,34 +12,37 @@ from django.utils.translation import gettext as _ from django.views.generic import TemplateView from django.views.generic.edit import FormView -from plinth import __version__, actions, package -from plinth.errors import ActionError +from plinth import __version__, package from plinth.modules import first_boot, upgrades from plinth.views import AppView +from . import privileged from .forms import BackportsFirstbootForm, ConfigureForm, UpdateFirstbootForm class UpgradesConfigurationView(AppView): """Serve configuration page.""" + form_class = ConfigureForm success_url = reverse_lazy('upgrades:index') template_name = "upgrades_configure.html" app_id = 'upgrades' def get_initial(self): + """Return the initial values for the form.""" return { - 'auto_upgrades_enabled': upgrades.is_enabled(), + 'auto_upgrades_enabled': privileged.check_auto(), 'dist_upgrade_enabled': upgrades.is_dist_upgrade_enabled() } def get_context_data(self, *args, **kwargs): + """Add additional context data for template.""" context = super().get_context_data(*args, **kwargs) context['can_activate_backports'] = upgrades.can_activate_backports() context['is_backports_requested'] = upgrades.is_backports_requested() context['is_busy'] = (_is_updating() or package.is_package_manager_busy()) - context['log'] = get_log() + context['log'] = privileged.get_log() context['refresh_page_sec'] = 3 if context['is_busy'] else None context['version'] = __version__ context['new_version'] = is_newer_version_available() @@ -58,10 +60,10 @@ class UpgradesConfigurationView(AppView): try: if new_status['auto_upgrades_enabled']: - upgrades.enable() + privileged.enable_auto() else: - upgrades.disable() - except ActionError as exception: + privileged.disable_auto() + except Exception as exception: error = exception.args[2] messages.error( self.request, @@ -89,14 +91,14 @@ class UpgradesConfigurationView(AppView): def is_newer_version_available(): - """Returns whether a newer Freedombox version is available.""" + """Return whether a newer Freedombox version is available.""" cache = Cache() freedombox = cache['freedombox'] return not freedombox.candidate.is_installed def get_os_release(): - """Returns the Debian release number and name.""" + """Return the Debian release number and name.""" output = 'Error: Cannot read PRETTY_NAME in /etc/os-release.' with open('/etc/os-release', 'r', encoding='utf-8') as release_file: for line in release_file: @@ -107,11 +109,6 @@ def get_os_release(): return output -def get_log(): - """Return the current log for unattended upgrades.""" - return actions.superuser_run('upgrades', ['get-log']) - - def _is_updating(): """Check if manually triggered update is running.""" command = ['systemctl', 'is-active', 'freedombox-manual-upgrade'] @@ -124,9 +121,9 @@ def upgrade(request): """Serve the upgrade page.""" if request.method == 'POST': try: - actions.superuser_run('upgrades', ['run']) + privileged.run() messages.success(request, _('Upgrade process started.')) - except ActionError: + except Exception: messages.error(request, _('Starting upgrade failed.')) return redirect(reverse_lazy('upgrades:index')) @@ -144,6 +141,7 @@ def activate_backports(request): class BackportsFirstbootView(FormView): """View to configure backports during first boot wizard.""" + template_name = 'backports-firstboot.html' form_class = BackportsFirstbootForm @@ -179,6 +177,7 @@ class BackportsFirstbootView(FormView): class UpdateFirstbootView(FormView): """View to run initial update during first boot wizard.""" + template_name = 'update-firstboot.html' form_class = UpdateFirstbootForm @@ -197,7 +196,7 @@ class UpdateFirstbootView(FormView): """Run update if selected, and mark step as done.""" self.update = form.cleaned_data['update_now'] if self.update: - actions.superuser_run('upgrades', ['run']) + privileged.run() first_boot.mark_step_done('initial_update') return super().form_valid(form) @@ -205,6 +204,7 @@ class UpdateFirstbootView(FormView): class UpdateFirstbootProgressView(TemplateView): """View to show initial update progress.""" + template_name = 'update-firstboot-progress.html' def get_context_data(self, *args, **kwargs): From 0c936512c442d56c5c5282f4dde689815e5ea787 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 15:14:20 -0700 Subject: [PATCH 62/90] wireguard: Us privileged decorator for actions Tests: - Functional tests work (uninstall test fails to no backup component, intermittent failure) - Showing status information works - In the main app page for server and clients - When showing server details - When showing client details Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- .../modules/wireguard/privileged.py | 49 ++++--------------- plinth/modules/wireguard/utils.py | 11 ++--- 2 files changed, 13 insertions(+), 47 deletions(-) rename actions/wireguard => plinth/modules/wireguard/privileged.py (56%) mode change 100755 => 100644 diff --git a/actions/wireguard b/plinth/modules/wireguard/privileged.py old mode 100755 new mode 100644 similarity index 56% rename from actions/wireguard rename to plinth/modules/wireguard/privileged.py index 48ab2627f..34a61d0f0 --- a/actions/wireguard +++ b/plinth/modules/wireguard/privileged.py @@ -1,40 +1,27 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for WireGuard. -""" +"""Configuration helper for WireGuard.""" -import argparse -import json import subprocess +from plinth.actions import privileged + SERVER_INTERFACE = 'wg0' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('get-info', - help='Get info for each configured interface') - - subparsers.required = True - return parser.parse_args() - - -def _get_info(): +@privileged +def get_info() -> dict[str, dict]: """Return info for each configured interface.""" output = subprocess.check_output(['wg', 'show', 'all', 'dump']).decode().strip() lines = output.split('\n') - interfaces = {} + interfaces: dict[str, dict] = {} for line in lines: if not line: continue - fields = line.split() - fields = [field if field != '(none)' else None for field in fields] + fields = [ + field if field != '(none)' else None for field in line.split() + ] interface_name = fields[0] if interface_name in interfaces: latest_handshake = int(fields[5]) if int(fields[5]) else None @@ -61,21 +48,3 @@ def _get_info(): } return interfaces - - -def subcommand_get_info(_): - """Print info for each configured interface.""" - print(json.dumps(_get_info())) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/wireguard/utils.py b/plinth/modules/wireguard/utils.py index 2db3d19de..2d7b56c79 100644 --- a/plinth/modules/wireguard/utils.py +++ b/plinth/modules/wireguard/utils.py @@ -1,19 +1,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Utilities for managing WireGuard. -""" +"""Utilities for managing WireGuard.""" import datetime -import json import logging import subprocess import time -from plinth import actions from plinth import app as app_module from plinth import network from plinth.utils import import_from_gi +from . import privileged + nm = import_from_gi('NM', '1.0') IP_TEMPLATE = '10.84.0.{}' @@ -70,8 +68,7 @@ def get_nm_info(): def get_info(): """Return server and clients info.""" - output = actions.superuser_run('wireguard', ['get-info']) - status = json.loads(output) + status = privileged.get_info() nm_info = get_nm_info() From d68a84d245e098d5b132268e1eee2a46574d7dc1 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 15:19:35 -0700 Subject: [PATCH 63/90] wordpress: Use privileged decorator for actions Tests: - Functional tests work (when libpam-tmpdir is removed) - Backup and restore of database works - Initial setup work - Configuration file is created - Database is created - Website is accessible - Enabling/disabling public access works - Configuration file created/deleted - App page show proper status Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/wordpress/__init__.py | 15 ++--- .../modules/wordpress/privileged.py | 61 ++++++------------- plinth/modules/wordpress/views.py | 18 ++---- 3 files changed, 29 insertions(+), 65 deletions(-) rename actions/wordpress => plinth/modules/wordpress/privileged.py (78%) mode change 100755 => 100644 diff --git a/plinth/modules/wordpress/__init__.py b/plinth/modules/wordpress/__init__.py index ac4f6519d..c07872e89 100644 --- a/plinth/modules/wordpress/__init__.py +++ b/plinth/modules/wordpress/__init__.py @@ -1,11 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure WordPress. -""" +"""FreedomBox app to configure WordPress.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon @@ -15,9 +12,7 @@ from plinth.modules.firewall.components import Firewall from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest - -PUBLIC_ACCESS_FILE = '/etc/wordpress/is_public' +from . import manifest, privileged _description = [ _('WordPress is a popular way to create and manage websites and blogs. ' @@ -106,7 +101,7 @@ class WordPressApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('wordpress', ['setup']) + privileged.setup() if not old_version: self.enable() elif old_version < 3: @@ -120,9 +115,9 @@ class WordPressBackupRestore(BackupRestore): def backup_pre(self, packet): """Save database contents.""" super().backup_pre(packet) - actions.superuser_run('wordpress', ['dump-database']) + privileged.dump_database() def restore_post(self, packet): """Restore database contents.""" super().restore_post(packet) - actions.superuser_run('wordpress', ['restore-database']) + privileged.restore_database() diff --git a/actions/wordpress b/plinth/modules/wordpress/privileged.py old mode 100755 new mode 100644 similarity index 78% rename from actions/wordpress rename to plinth/modules/wordpress/privileged.py index ba96e8a8d..28ec93112 --- a/actions/wordpress +++ b/plinth/modules/wordpress/privileged.py @@ -1,10 +1,6 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for WordPress. -""" +"""Configuration helper for WordPress.""" -import argparse import os import pathlib import random @@ -15,7 +11,9 @@ import subprocess import augeas from plinth import action_utils -from plinth.modules.wordpress import PUBLIC_ACCESS_FILE +from plinth.actions import privileged + +PUBLIC_ACCESS_FILE = '/etc/wordpress/is_public' _config_file_path = pathlib.Path('/etc/wordpress/config-default.php') _static_config_file_path = pathlib.Path('/etc/wordpress/freedombox-static.php') @@ -27,26 +25,8 @@ DB_NAME = 'wordpress_fbx' DB_USER = 'wordpress_fbx' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', - help='Create initial configuration and database') - subparsers.add_parser('dump-database', help='Dump database to file') - subparsers.add_parser('restore-database', - help='Restore database from file') - subparser = subparsers.add_parser('set-public', - help='Allow/disallow public access') - subparser.add_argument('--enable', choices=('True', 'False'), - help='Whether to enable or disable public acceess') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_setup(_): +@privileged +def setup(): """Create initial configuration and database for WordPress.""" if _db_file_path.exists() or _config_file_path.exists(): if _config_file_path.exists(): @@ -144,10 +124,11 @@ def _upgrade_config_file(): _config_file_path.write_text('\n'.join(lines), encoding='utf-8') -def subcommand_set_public(arguments): +@privileged +def set_public(enable: bool): """Allow/disallow public access.""" public_access_file = pathlib.Path(PUBLIC_ACCESS_FILE) - if arguments.enable == 'True': + if enable: public_access_file.touch() else: public_access_file.unlink(missing_ok=True) @@ -155,7 +136,13 @@ def subcommand_set_public(arguments): action_utils.service_reload('apache2') -def subcommand_dump_database(_): +def is_public() -> bool: + """Return whether public access is enabled.""" + return pathlib.Path(PUBLIC_ACCESS_FILE).exists() + + +@privileged +def dump_database(): """Dump database to file.""" _db_backup_file.parent.mkdir(parents=True, exist_ok=True) with _db_backup_file.open('w', encoding='utf-8') as file_handle: @@ -165,7 +152,8 @@ def subcommand_dump_database(_): ], stdout=file_handle, check=True) -def subcommand_restore_database(_): +@privileged +def restore_database(): """Restore database from file.""" with _db_backup_file.open('r', encoding='utf-8') as file_handle: subprocess.run(['mysql', '--user', 'root'], stdin=file_handle, @@ -189,16 +177,3 @@ def _load_augeas(): aug.load() return aug - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/wordpress/views.py b/plinth/modules/wordpress/views.py index 1387a05dd..049f515e5 100644 --- a/plinth/modules/wordpress/views.py +++ b/plinth/modules/wordpress/views.py @@ -1,28 +1,25 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring WordPress. -""" - -import pathlib +"""FreedomBox app for configuring WordPress.""" from django.contrib import messages from django.utils.translation import gettext as _ -from plinth import actions, views +from plinth import views -from . import PUBLIC_ACCESS_FILE +from . import privileged from .forms import WordPressForm class WordPressAppView(views.AppView): """Serve configuration page.""" + form_class = WordPressForm app_id = 'wordpress' def get_initial(self): """Get the current WordPress settings.""" status = super().get_initial() - status['is_public'] = pathlib.Path(PUBLIC_ACCESS_FILE).exists() + status['is_public'] = privileged.is_public() return status def form_valid(self, form): @@ -30,10 +27,7 @@ class WordPressAppView(views.AppView): old_status = form.initial new_status = form.cleaned_data if old_status['is_public'] != new_status['is_public']: - actions.superuser_run( - 'wordpress', - ['set-public', '--enable', - str(new_status['is_public'])]) + privileged.set_public(new_status['is_public']) messages.success(self.request, _('Configuration updated')) return super().form_valid(form) From 7f8eebce4c23fa3550fe77f00eb48074949567f0 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 26 Aug 2022 15:32:18 -0700 Subject: [PATCH 64/90] zoph: Use privileged decorator for actions Tests: - Functional tests work - Dump/restore of database works - Initial setup works - MySQL Database is created - Configuration options are set - OSM is enabled by default - User who installed the app becomes admin - Setting configuration works - Enabling OSM - Setting admin user Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/zoph/__init__.py | 40 ++------- .../zoph => plinth/modules/zoph/privileged.py | 84 ++++++------------- plinth/modules/zoph/views.py | 20 ++--- 3 files changed, 42 insertions(+), 102 deletions(-) rename actions/zoph => plinth/modules/zoph/privileged.py (59%) mode change 100755 => 100644 diff --git a/plinth/modules/zoph/__init__.py b/plinth/modules/zoph/__init__.py index 71ac501a1..7ec541429 100644 --- a/plinth/modules/zoph/__init__.py +++ b/plinth/modules/zoph/__init__.py @@ -1,14 +1,10 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure Zoph web application -""" +"""FreedomBox app to configure Zoph web application.""" -import json import logging from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.modules.apache.components import Webserver @@ -17,7 +13,7 @@ from plinth.modules.firewall.components import Firewall from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged logger = logging.getLogger(__name__) @@ -88,45 +84,21 @@ class ZophApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" - actions.superuser_run('zoph', ['pre-install']) + privileged.pre_install() super().setup(old_version) - actions.superuser_run('zoph', ['setup']) + privileged.setup() self.enable() -def set_configuration(admin_user=None, enable_osm=None): - """Configure Zoph.""" - args = [] - if admin_user: - args += ['--admin-user', admin_user] - - if enable_osm is not None: - args += ['--enable-osm', str(enable_osm)] - - actions.superuser_run('zoph', ['set-configuration'] + args) - - -def is_configured(): - """Return whether the Zoph app is configured.""" - output = actions.superuser_run('zoph', ['is-configured']) - return output.strip() == 'true' - - -def get_configuration(): - """Return full configuration of Zoph.""" - configuration = actions.superuser_run('zoph', ['get-configuration']) - return json.loads(configuration) - - class ZophBackupRestore(BackupRestore): """Component to backup/restore Zoph database""" def backup_pre(self, packet): """Save database contents.""" super().backup_pre(packet) - actions.superuser_run('zoph', ['dump-database']) + privileged.dump_database() def restore_post(self, packet): """Restore database contents.""" super().restore_post(packet) - actions.superuser_run('zoph', ['restore-database']) + privileged.restore_database() diff --git a/actions/zoph b/plinth/modules/zoph/privileged.py old mode 100755 new mode 100644 similarity index 59% rename from actions/zoph rename to plinth/modules/zoph/privileged.py index ce8d7da61..eb555f44b --- a/actions/zoph +++ b/plinth/modules/zoph/privileged.py @@ -1,47 +1,21 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for Zoph server. -""" +"""Configuration helper for Zoph server.""" -import argparse import configparser -import json import os import re import subprocess +from typing import Optional from plinth import action_utils +from plinth.actions import privileged APACHE_CONF = '/etc/apache2/conf-available/zoph.conf' DB_BACKUP_FILE = '/var/lib/plinth/backups-data/zoph-database.sql' -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('pre-install', - help='Perform Zoph pre-install configuration') - subparser = subparsers.add_parser('setup', - help='Perform Zoph configuration setup') - subparsers.add_parser('get-configuration', - help='Return the current configuration') - subparser = subparsers.add_parser('set-configuration', - help='Configure zoph') - subparser.add_argument('--admin-user', help='Name of the admin user') - subparser.add_argument('--enable-osm', help='Enable OpenSteetMap maps') - subparsers.add_parser('is-configured', help='return true if configured') - subparsers.add_parser('dump-database', help='Dump database to file') - subparsers.add_parser('restore-database', - help='Restore database from file') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_pre_install(_): +@privileged +def pre_install(): """Preseed debconf values before packages are installed.""" action_utils.debconf_set_selections([ 'zoph zoph/dbconfig-install boolean true', @@ -49,7 +23,8 @@ def subcommand_pre_install(_): ]) -def subcommand_get_configuration(_): +@privileged +def get_configuration() -> dict[str, str]: """Return the current configuration.""" configuration = {} process = subprocess.run(['zoph', '--dump-config'], stdout=subprocess.PIPE, @@ -58,7 +33,7 @@ def subcommand_get_configuration(_): name, value = line.partition(':')[::2] configuration[name.strip()] = value[1:] - print(json.dumps(configuration)) + return configuration def _zoph_configure(key, value): @@ -66,7 +41,8 @@ def _zoph_configure(key, value): subprocess.run(['zoph', '--config', key, value], check=True) -def subcommand_setup(_): +@privileged +def setup(): """Setup Zoph configuration.""" _zoph_configure('import.enable', 'true') _zoph_configure('import.upload', 'true') @@ -88,19 +64,20 @@ def _get_db_name(): return config['zoph']['db_name'].strip('"') -def subcommand_set_configuration(arguments): +@privileged +def set_configuration(enable_osm: Optional[bool] = None, + admin_user: Optional[str] = None): """Setup Zoph Apache configuration.""" _zoph_configure('interface.user.remote', 'true') # Note that using OpenSteetmap as a mapping provider is a very nice # feature, but some people may regard its use as a privacy issue - if arguments.enable_osm: - value = 'osm' if arguments.enable_osm == 'True' else '' + if enable_osm is not None: + value = 'osm' if enable_osm else '' _zoph_configure('maps.provider', value) - if arguments.admin_user: + if admin_user: # Edit the database to rename the admin user to FreedomBox admin user. - admin_user = arguments.admin_user if not re.match(r'^[\w.@][\w.@-]+\Z', admin_user, flags=re.ASCII): # Check to avoid SQL injection raise ValueError('Invalid username') @@ -112,13 +89,16 @@ def subcommand_set_configuration(arguments): check=True) -def subcommand_is_configured(_): - """Print whether zoph app is configured.""" - subprocess.run(['zoph', '--get-config', 'interface.user.remote'], - check=True) +@privileged +def is_configured() -> bool: + """Return whether zoph app is configured.""" + process = subprocess.run(['zoph', '--get-config', 'interface.user.remote'], + stdout=subprocess.PIPE, check=True) + return process.stdout.decode().strip() == 'true' -def subcommand_dump_database(_): +@privileged +def dump_database(): """Dump database to file.""" db_name = _get_db_name() os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True) @@ -127,23 +107,11 @@ def subcommand_dump_database(_): check=True) -def subcommand_restore_database(_): +@privileged +def restore_database(): """Restore database from file.""" db_name = _get_db_name() subprocess.run(['mysqladmin', '--force', 'drop', db_name], check=False) subprocess.run(['mysqladmin', 'create', db_name], check=True) with open(DB_BACKUP_FILE, 'r', encoding='utf-8') as db_restore_file: subprocess.run(['mysql', db_name], stdin=db_restore_file, check=True) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/zoph/views.py b/plinth/modules/zoph/views.py index 485fa30b5..f7689de9e 100644 --- a/plinth/modules/zoph/views.py +++ b/plinth/modules/zoph/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for configuring Zoph photo organiser. -""" +"""FreedomBox app for configuring Zoph photo organiser.""" import logging @@ -14,9 +12,8 @@ from django.views.generic import TemplateView from plinth import app as app_module from plinth import views -from plinth.errors import ActionError -from plinth.modules import zoph +from . import privileged from .forms import ZophForm logger = logging.getLogger(__name__) @@ -24,6 +21,7 @@ logger = logging.getLogger(__name__) class SetupView(TemplateView): """Show zoph setup page.""" + template_name = 'zoph-pre-setup.html' success_url = reverse_lazy('zoph:index') @@ -38,18 +36,19 @@ class SetupView(TemplateView): def post(self, _request, *args, **kwargs): """Handle form submission.""" admin_user = self.request.user.get_username() - zoph.set_configuration(admin_user=admin_user) + privileged.set_configuration(admin_user=admin_user) return HttpResponseRedirect(reverse_lazy('zoph:index')) class ZophAppView(views.AppView): """App configuration page.""" + form_class = ZophForm app_id = 'zoph' def dispatch(self, request, *args, **kwargs): """Redirect to setup page if setup is not done yet.""" - if not zoph.is_configured(): + if not privileged.is_configured(): return redirect('zoph:setup') return super().dispatch(request, *args, **kwargs) @@ -57,7 +56,7 @@ class ZophAppView(views.AppView): def get_initial(self): """Get the current settings from Zoph.""" status = super().get_initial() - config = zoph.get_configuration() + config = privileged.get_configuration() status['enable_osm'] = (config['maps.provider'] == 'osm') return status @@ -67,9 +66,10 @@ class ZophAppView(views.AppView): new_status = form.cleaned_data if old_status['enable_osm'] != new_status['enable_osm']: try: - zoph.set_configuration(enable_osm=new_status['enable_osm']) + privileged.set_configuration( + enable_osm=new_status['enable_osm']) messages.success(self.request, _('Configuration updated.')) - except ActionError: + except Exception: messages.error(self.request, _('An error occurred during configuration.')) From 6072b1cea684cc2b83f1b89cbdc89143bbabd557 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 1 Sep 2022 22:37:36 -0700 Subject: [PATCH 65/90] backups: Use privileged decorator for sshfs actions Tests: - Mounting an SSH repository works - If an known error is thrown during mounting, a simplified error is shown. - Unmounting an SSH repository works - If an known error is thrown during mounting, a simplified error is shown. - Correct status of whether the repository is mounted is shown. - If an known error is thrown during mounting, a simplified error is shown. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- .../modules/backups/privileged.py | 88 ++++--------------- plinth/modules/backups/repository.py | 57 ++++++------ 2 files changed, 46 insertions(+), 99 deletions(-) rename actions/sshfs => plinth/modules/backups/privileged.py (50%) mode change 100755 => 100644 diff --git a/actions/sshfs b/plinth/modules/backups/privileged.py old mode 100755 new mode 100644 similarity index 50% rename from actions/sshfs rename to plinth/modules/backups/privileged.py index badfc700b..5ba4c91b6 --- a/actions/sshfs +++ b/plinth/modules/backups/privileged.py @@ -1,15 +1,10 @@ -#!/usr/bin/python3 -# -*- mode: python -*- # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Actions for sshfs. -""" +"""Configure backups and sshfs.""" -import argparse -import json import os import subprocess -import sys + +from plinth.actions import privileged TIMEOUT = 30 @@ -18,40 +13,15 @@ class AlreadyMountedError(Exception): """Exception raised when mount point is already mounted.""" -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - mount = subparsers.add_parser('mount', help='mount an ssh filesystem') - mount.add_argument('--mountpoint', help='Local mountpoint', required=True) - mount.add_argument('--path', help='Remote ssh path to mount', - required=True) - mount.add_argument('--ssh-keyfile', help='Path of private ssh key', - default=None, required=False) - mount.add_argument('--user-known-hosts-file', - help='Path to a custom known_hosts file', - default='/dev/null') - umount = subparsers.add_parser('umount', help='unmount an ssh filesystem') - umount.add_argument('--mountpoint', help='Mountpoint to unmount', - required=True) - is_mounted = subparsers.add_parser( - 'is-mounted', help='Check whether a mountpoint is mounted') - is_mounted.add_argument('--mountpoint', help='Mountpoint to check', - required=True) - - subparsers.required = True - return parser.parse_args() - - -def subcommand_mount(arguments): +@privileged +def mount(mountpoint: str, remote_path: str, ssh_keyfile: str = None, + password: str = None, user_known_hosts_file: str = '/dev/null'): """Mount a remote ssh path via sshfs.""" try: - validate_mountpoint(arguments.mountpoint) + _validate_mountpoint(mountpoint) except AlreadyMountedError: return - remote_path = arguments.path kwargs = {} # the shell would expand ~/ to the local home directory remote_path = remote_path.replace('~/', '').replace('~', '') @@ -65,15 +35,14 @@ def subcommand_mount(arguments): # the course of ~11 days, and leaving the system in such state that the # only solution is a reboot. cmd = [ - 'sshfs', remote_path, arguments.mountpoint, '-o', - f'UserKnownHostsFile={arguments.user_known_hosts_file}', '-o', + 'sshfs', remote_path, mountpoint, '-o', + f'UserKnownHostsFile={user_known_hosts_file}', '-o', 'StrictHostKeyChecking=yes', '-o', 'reconnect', '-o', 'ServerAliveInterval=15', '-o', 'ServerAliveCountMax=3' ] - if arguments.ssh_keyfile: - cmd += ['-o', 'IdentityFile=' + arguments.ssh_keyfile] + if ssh_keyfile: + cmd += ['-o', 'IdentityFile=' + ssh_keyfile] else: - password = read_password() if not password: raise ValueError('mount requires either a password or ssh_keyfile') cmd += ['-o', 'password_stdin'] @@ -82,13 +51,14 @@ def subcommand_mount(arguments): subprocess.run(cmd, check=True, timeout=TIMEOUT, **kwargs) -def subcommand_umount(arguments): +@privileged +def subcommand_umount(mountpoint: str): """Unmount a mountpoint.""" - subprocess.run(['umount', arguments.mountpoint], check=True) + subprocess.run(['umount', mountpoint], check=True) -def validate_mountpoint(mountpoint): - """Check that the folder is empty, and create it if it doesn't exist""" +def _validate_mountpoint(mountpoint): + """Check that the folder is empty, and create it if it doesn't exist.""" if os.path.exists(mountpoint): if _is_mounted(mountpoint): raise AlreadyMountedError('Mountpoint %s already mounted' % @@ -111,27 +81,7 @@ def _is_mounted(mountpoint): return False -def subcommand_is_mounted(arguments): +@privileged +def is_mounted(arguments) -> bool: """Print whether a path is already mounted.""" - print(json.dumps(_is_mounted(arguments.mountpoint))) - - -def read_password(): - """Read the password from stdin.""" - if sys.stdin.isatty(): - return '' - - return ''.join(sys.stdin) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() + return _is_mounted(arguments.mountpoint) diff --git a/plinth/modules/backups/repository.py b/plinth/modules/backups/repository.py index 25aca4aef..f63ae3186 100644 --- a/plinth/modules/backups/repository.py +++ b/plinth/modules/backups/repository.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Remote and local Borg backup repositories -""" +"""Remote and local Borg backup repositories.""" import abc import contextlib @@ -19,7 +17,7 @@ from plinth import actions, cfg from plinth.errors import ActionError from plinth.utils import format_lazy -from . import (_backup_handler, api, errors, get_known_hosts_path, +from . import (_backup_handler, api, errors, get_known_hosts_path, privileged, restore_archive_handler, split_path, store) from .schedule import Schedule @@ -213,6 +211,14 @@ class BaseBorgRepository(abc.ABC): return {} + @contextlib.contextmanager + def _handle_errors(self): + """Parse exceptions into more specific ones.""" + try: + yield + except Exception as exception: + self.reraise_known_error(exception) + def _run(self, cmd, arguments, superuser=True, **kwargs): """Run a backups or sshfs action script command.""" try: @@ -418,9 +424,8 @@ class SshBorgRepository(BaseBorgRepository): @property def is_mounted(self): """Return whether remote path is mounted locally.""" - output = self._run('sshfs', - ['is-mounted', '--mountpoint', self._mountpoint]) - return json.loads(output) + with self._handle_errors(): + return privileged.is_mounted(self._mountpoint) def initialize(self): """Initialize the repository after mounting the target directory.""" @@ -432,22 +437,27 @@ class SshBorgRepository(BaseBorgRepository): """Mount the remote path locally using sshfs.""" if self.is_mounted: return + known_hosts_path = get_known_hosts_path() - arguments = [ - 'mount', '--mountpoint', self._mountpoint, '--path', self._path, - '--user-known-hosts-file', - str(known_hosts_path) - ] - arguments, kwargs = self._append_sshfs_arguments( - arguments, self.credentials) - self._run('sshfs', arguments, **kwargs) + kwargs = {'user_known_hosts_file': str(known_hosts_path)} + if 'ssh_password' in self.credentials and self.credentials[ + 'ssh_password']: + kwargs['password'] = self.credentials['ssh_password'] + + if 'ssh_keyfile' in self.credentials and self.credentials[ + 'ssh_keyfile']: + kwargs['ssh_keyfile'] = self.credentials['ssh_keyfile'] + + with self._handle_errors(): + privileged.mount(self._mountpoint, self._path, **kwargs) def umount(self): """Unmount the remote path that was mounted locally using sshfs.""" if not self.is_mounted: return - self._run('sshfs', ['umount', '--mountpoint', self._mountpoint]) + with self._handle_errors(): + privileged.umount(self._mountpoint) def _umount_ignore_errors(self): """Run unmount operation and ignore any exceptions thrown.""" @@ -457,7 +467,7 @@ class SshBorgRepository(BaseBorgRepository): logger.warning('Unable to unmount repository', exc_info=exception) def remove(self): - """Remove a repository from the kvstore and delete its mountpoint""" + """Remove a repository from the kvstore and delete its mountpoint.""" self.umount() store.delete(self.uuid) try: @@ -471,19 +481,6 @@ class SshBorgRepository(BaseBorgRepository): except Exception as err: logger.error(err) - @staticmethod - def _append_sshfs_arguments(arguments, credentials): - """Add credentials to a run command and kwargs""" - kwargs = {} - - if 'ssh_password' in credentials and credentials['ssh_password']: - kwargs['input'] = credentials['ssh_password'].encode() - - if 'ssh_keyfile' in credentials and credentials['ssh_keyfile']: - arguments += ['--ssh-keyfile', credentials['ssh_keyfile']] - - return (arguments, kwargs) - def _ensure_remote_directory(self): """Create remote SSH directory if it does not exist.""" username, hostname, dir_path = split_path(self.path) From 49e4ebf8f96ca43b9df30158b35a6ae8f9cfe6fc Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 2 Sep 2022 08:58:54 -0700 Subject: [PATCH 66/90] samba: Use privileged decorator for actions Tests: - Functional tests work (uninstall fails) - Initial setup works - File /etc/default/samba is updated - Dump and restore share during backup/restore works - Setup run successfully during restore - /var/lib/plinth/backups-data/samba-shares-dump.conf - Adding/deleting a share works - Not tested: Add a share on ntfs or vfat file system works - Showing list of shares in app view works - Getting list of samba users in app view works - Handling errors during add/delete share works Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/samba/__init__.py | 42 ++------ .../modules/samba/privileged.py | 99 ++++++------------- plinth/modules/samba/tests/test_views.py | 32 +++--- plinth/modules/samba/views.py | 16 +-- plinth/modules/storage/forms.py | 5 +- 5 files changed, 62 insertions(+), 132 deletions(-) rename actions/samba => plinth/modules/samba/privileged.py (78%) mode change 100755 => 100644 diff --git a/plinth/modules/samba/__init__.py b/plinth/modules/samba/__init__.py index 3730da2fd..cab73b3b8 100644 --- a/plinth/modules/samba/__init__.py +++ b/plinth/modules/samba/__init__.py @@ -1,17 +1,13 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to configure samba. -""" +"""FreedomBox app to configure samba.""" import grp -import json import pwd import socket from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import frontpage, menu from plinth.daemon import Daemon @@ -21,7 +17,7 @@ from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest +from . import manifest, privileged _description = [ _('Samba allows to share files and folders between FreedomBox and ' @@ -102,7 +98,7 @@ class SambaApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('samba', ['setup']) + privileged.setup() self.enable() @@ -112,37 +108,24 @@ class SambaBackupRestore(BackupRestore): def backup_pre(self, packet): """Save registry share configuration.""" super().backup_pre(packet) - actions.superuser_run('samba', ['dump-shares']) + privileged.dump_shares() def restore_post(self, packet): """Restore configuration.""" super().restore_post(packet) - actions.superuser_run('samba', ['setup']) - actions.superuser_run('samba', ['restore-shares']) + privileged.setup() + privileged.restore_shares() def add_share(mount_point, share_type, filesystem): """Add a share.""" - command = [ - 'add-share', '--mount-point', mount_point, '--share-type', share_type - ] - if filesystem in ['ntfs', 'vfat']: - command = command + ['--windows-filesystem'] - actions.superuser_run('samba', command) - - -def delete_share(mount_point, share_type): - """Delete a share.""" - actions.superuser_run('samba', [ - 'delete-share', '--mount-point', mount_point, '--share-type', - share_type - ]) + windows_filesystem = (filesystem in ['ntfs', 'vfat']) + privileged.add_share(mount_point, share_type, windows_filesystem) def get_users(): """Get non-system users who are in the freedombox-share or admin group.""" - output = actions.superuser_run('samba', ['get-users']) - samba_users = json.loads(output)['users'] + samba_users = privileged.get_users() group_users = grp.getgrnam('freedombox-share').gr_mem + grp.getgrnam( 'admin').gr_mem @@ -158,10 +141,3 @@ def get_users(): 'password_re_enter_needed': sorted(set(allowed_users) - set(samba_users)) } - - -def get_shares(): - """Get defined shares.""" - output = actions.superuser_run('samba', ['get-shares']) - - return json.loads(output) diff --git a/actions/samba b/plinth/modules/samba/privileged.py old mode 100755 new mode 100644 similarity index 78% rename from actions/samba rename to plinth/modules/samba/privileged.py index 991a6bbce..e91857926 --- a/actions/samba +++ b/plinth/modules/samba/privileged.py @@ -1,16 +1,13 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for samba. -""" +"""Configuration helper for samba.""" -import argparse import configparser -import json import os import shutil import subprocess +from plinth.actions import privileged + SHARES_CONF_BACKUP_FILE = '/var/lib/plinth/backups-data/samba-shares-dump.conf' DEFAULT_FILE = '/etc/default/samba' @@ -45,42 +42,6 @@ CONF = r''' ''' # noqa: E501 -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Configure samba after install') - - subparsers.add_parser('get-shares', help='Get configured samba shares') - - subparsers.add_parser('get-users', help='Get users from Samba database') - - subparser = subparsers.add_parser('add-share', help='Add new samba share') - subparser.add_argument('--mount-point', help='Path of the mount point', - required=True) - subparser.add_argument('--share-type', help='Type of the share', - required=True, choices=['open', 'group', 'home']) - subparser.add_argument('--windows-filesystem', required=False, - default=False, action='store_true', - help='Path is Windows filesystem') - - subparser = subparsers.add_parser( - 'delete-share', help='Delete a samba share configuration') - subparser.add_argument('--mount-point', help='Path of the mount point', - required=True) - subparser.add_argument('--share-type', help='Type of the share', - required=True, choices=['open', 'group', 'home']) - - subparsers.add_parser('dump-shares', - help='Dump share configuration to file') - subparsers.add_parser('restore-shares', - help='Restore share configuration from file') - - subparsers.required = True - return parser.parse_args() - - def _close_share(share_name): """Disconnect all samba users who are connected to the share.""" subprocess.check_call(['smbcontrol', 'smbd', 'close-share', share_name]) @@ -182,7 +143,7 @@ def _get_mount_point(path): return path.split(subpath)[0] -def _get_shares(): +def _get_shares() -> list[dict[str, str]]: """Get shares.""" shares = [] output = subprocess.check_output(['net', 'conf', 'list']) @@ -265,40 +226,50 @@ def _set_share_permissions(directory): subprocess.check_call(['setfacl', '-Rdm', 'g::rwX', directory]) -def subcommand_add_share(arguments): +@privileged +def add_share(mount_point: str, share_type: str, windows_filesystem: bool): """Create a samba share.""" - mount_point = os.path.normpath(arguments.mount_point) + if share_type not in ('open', 'group', 'home'): + raise ValueError('Invalid share type') + + mount_point = os.path.normpath(mount_point) if not os.path.ismount(mount_point): raise RuntimeError( 'Path "{0}" is not a mount point.'.format(mount_point)) - _create_share(mount_point, arguments.share_type, - arguments.windows_filesystem) + _create_share(mount_point, share_type, windows_filesystem) -def subcommand_delete_share(arguments): +@privileged +def delete_share(mount_point: str, share_type: str): """Delete a samba share configuration.""" - mount_point = os.path.normpath(arguments.mount_point) + if share_type not in ('open', 'group', 'home'): + raise ValueError('Invalid share type') + + mount_point = os.path.normpath(mount_point) shares = _get_shares() for share in shares: if share['mount_point'] == mount_point and share[ - 'share_type'] == arguments.share_type: + 'share_type'] == share_type: _close_share(share['name']) _conf_command(['delshare', share['name']]) -def subcommand_get_shares(_): +@privileged +def get_shares() -> list[dict[str, str]]: """Get samba shares.""" - print(json.dumps(_get_shares())) + return _get_shares() -def subcommand_get_users(_): +@privileged +def get_users() -> list[str]: """Get users from Samba database.""" output = subprocess.check_output(['pdbedit', '-L']).decode() samba_users = [line.split(':')[0] for line in output.split()] - print(json.dumps({'users': samba_users})) + return samba_users -def subcommand_setup(_): +@privileged +def setup(): """Configure samba, use custom samba config file.""" from plinth import action_utils with open(CONF_PATH, 'w', encoding='utf-8') as file_handle: @@ -310,7 +281,8 @@ def subcommand_setup(_): action_utils.service_restart('smbd') -def subcommand_dump_shares(_): +@privileged +def dump_shares(): """Dump registy share configuration.""" os.makedirs(os.path.dirname(SHARES_CONF_BACKUP_FILE), exist_ok=True) with open(SHARES_CONF_BACKUP_FILE, 'w', encoding='utf-8') as backup_file: @@ -318,22 +290,11 @@ def subcommand_dump_shares(_): subprocess.run(command, stdout=backup_file, check=True) -def subcommand_restore_shares(_): +@privileged +def restore_shares(): """Restore registy share configuration.""" if not os.path.exists(SHARES_CONF_BACKUP_FILE): raise RuntimeError( 'Backup file {0} does not exist.'.format(SHARES_CONF_BACKUP_FILE)) _conf_command(['drop']) _conf_command(['import', SHARES_CONF_BACKUP_FILE]) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/samba/tests/test_views.py b/plinth/modules/samba/tests/test_views.py index 42f97733f..70dd0c061 100644 --- a/plinth/modules/samba/tests/test_views.py +++ b/plinth/modules/samba/tests/test_views.py @@ -3,7 +3,7 @@ Tests for samba views. """ -import json +import pathlib import urllib from unittest.mock import patch @@ -12,11 +12,11 @@ from django import urls from django.contrib.messages.storage.fallback import FallbackStorage from plinth import module_loader -from plinth.errors import ActionError from plinth.modules.samba import views # For all tests, use plinth.urls instead of urls configured for testing pytestmark = pytest.mark.urls('plinth.urls') +setfacl_path = pathlib.Path('/usr/bin/setfacl') USERS = {"access_ok": ["testuser"], 'password_re_enter_needed': []} @@ -70,18 +70,12 @@ def fixture_samba_urls(): yield -def action_run(action, options, **kwargs): - """Action return values.""" - if action == 'samba' and options == ['get-shares']: - return json.dumps(SHARES) - - return None - - @pytest.fixture(autouse=True) -def samba_patch_actions(): - """Patch actions scripts runner.""" - with patch('plinth.actions.superuser_run', side_effect=action_run): +def samba_patch_privileged(): + """Patch privileged scripts runner.""" + with patch('plinth.modules.samba.privileged.get_shares') as get_shares, \ + patch('plinth.modules.samba.privileged.delete_share'): + get_shares.return_value = SHARES yield @@ -120,6 +114,7 @@ def test_samba_shares_view(rf): assert response.status_code == 200 +@pytest.mark.skipif(not setfacl_path.exists(), reason='setfacl not installed') def test_enable_samba_share_view(rf): """Test that enabling share sends correct success message.""" form_data = {'filesystem_type': 'ext4', 'open_share': 'enable'} @@ -138,7 +133,7 @@ def test_enable_samba_share_failed_view(rf): mount_point = urllib.parse.quote('/') error_message = 'Sharing failed' with patch('plinth.modules.samba.add_share', - side_effect=ActionError(error_message)): + side_effect=RuntimeError(error_message)): response, messages = make_request(rf.post('', data=form_data), views.share, mount_point=mount_point) @@ -165,13 +160,12 @@ def test_disable_samba_share_failed_view(rf): form_data = {'filesystem_type': 'ext4', 'open_share': 'disable'} mount_point = urllib.parse.quote('/') error_message = 'Unsharing failed' - with patch('plinth.modules.samba.delete_share', - side_effect=ActionError(error_message)): + with patch('plinth.modules.samba.privileged.delete_share', + side_effect=RuntimeError(error_message)): response, messages = make_request(rf.post('', data=form_data), views.share, mount_point=mount_point) - assert list( - messages)[0].message == 'Error disabling share: {0}'.format( - error_message) + assert list(messages)[ + 0].message == 'Error disabling share: {0}'.format(error_message) assert response.status_code == 302 assert response.url == urls.reverse('samba:index') diff --git a/plinth/modules/samba/views.py b/plinth/modules/samba/views.py index 17ab9d87e..5df8f70b5 100644 --- a/plinth/modules/samba/views.py +++ b/plinth/modules/samba/views.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for samba module. -""" +"""Views for samba module.""" import logging import os @@ -15,9 +13,10 @@ from django.utils.translation import gettext as _ from django.views.decorators.http import require_POST from plinth import views -from plinth.errors import ActionError from plinth.modules import samba, storage +from . import privileged + logger = logging.getLogger(__name__) @@ -40,6 +39,7 @@ def get_share_mounts(): class SambaAppView(views.AppView): """Samba sharing basic configuration.""" + app_id = 'samba' template_name = 'samba.html' @@ -49,7 +49,7 @@ class SambaAppView(views.AppView): disks = get_share_mounts() context['disks'] = disks - shares = samba.get_shares() + shares = privileged.get_shares() shared_mounts = defaultdict(list) for share in shares: shared_mounts[share['mount_point']].append(share['share_type']) @@ -101,7 +101,7 @@ def share(request, mount_point): try: samba.add_share(mount_point, share_type, filesystem) messages.success(request, _('Share enabled.')) - except ActionError as exception: + except Exception as exception: logger.exception('Error enabling share') messages.error( request, @@ -109,9 +109,9 @@ def share(request, mount_point): error_message=exception)) elif action == 'disable': try: - samba.delete_share(mount_point, share_type) + privileged.delete_share(mount_point, share_type) messages.success(request, _('Share disabled.')) - except ActionError as exception: + except Exception as exception: logger.exception('Error disabling share') messages.error( request, diff --git a/plinth/modules/storage/forms.py b/plinth/modules/storage/forms.py index 3b7cab766..be419a827 100644 --- a/plinth/modules/storage/forms.py +++ b/plinth/modules/storage/forms.py @@ -3,7 +3,6 @@ Forms for directory selection. """ -import json import os from django import forms @@ -13,14 +12,14 @@ from django.utils.translation import gettext_lazy as _ from plinth import actions from plinth import app as app_module from plinth.modules import storage +from plinth.modules.samba import privileged as samba_privileged def get_available_samba_shares(): """Get available samba shares.""" available_shares = [] if _is_app_enabled('samba'): - samba_shares = json.loads( - actions.superuser_run('samba', ['get-shares'])) + samba_shares = samba_privileged.get_shares() if samba_shares: disks = storage.get_mounts() for share in samba_shares: From e3d0be28851b184b0949a503a36c362e3a991013 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 01:36:08 -0700 Subject: [PATCH 67/90] storage: Use privileged decorator for actions Tests: - SKIPPED: Functional tests work - DONE: Initial setup works - DONE: Root partition is expanded when space is available - DONE: When there is free space for root partition it shows up in the interface - DONE: Expand partition from user interface works - DONE: Getting storage usage information works - DONE: Disks and free space shown in app page - DONE: Showing share mounts in samba works - DONE: Backups add repository form shows disk choices - DONE: Samba shows proper list of mounted shares and unavailable shares - DONE: Directory validator works - DONE: In deluge and transmission - DONE: Auto-mounting a device works - DONE: Ejecting a mounted disk from UI works - DONE: Error are graciously handled Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/storage/__init__.py | 37 ++-- plinth/modules/storage/forms.py | 43 ++-- .../modules/storage/privileged.py | 191 +++++------------- plinth/modules/storage/tests/test_storage.py | 82 +++----- plinth/modules/storage/udisks2.py | 16 +- plinth/modules/storage/views.py | 20 +- 6 files changed, 133 insertions(+), 256 deletions(-) rename actions/storage => plinth/modules/storage/privileged.py (66%) mode change 100755 => 100644 diff --git a/plinth/modules/storage/__init__.py b/plinth/modules/storage/__init__.py index a823ccba6..7b29265e6 100644 --- a/plinth/modules/storage/__init__.py +++ b/plinth/modules/storage/__init__.py @@ -1,25 +1,21 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to manage storage. -""" +"""FreedomBox app to manage storage.""" import base64 import logging -import subprocess import psutil from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_noop -from plinth import actions from plinth import app as app_module from plinth import cfg, glib, menu -from plinth.errors import ActionError, PlinthError +from plinth.errors import PlinthError from plinth.modules.backups.components import BackupRestore from plinth.package import Packages from plinth.utils import format_lazy -from . import manifest, udisks2 +from . import manifest, privileged, udisks2 _description = [ format_lazy( @@ -77,19 +73,19 @@ class StorageApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - actions.superuser_run('storage', ['setup']) + privileged.setup() self.enable() disks = get_disks() root_device = get_root_device(disks) if is_expandable(root_device): try: - expand_partition(root_device) - except ActionError: + privileged.expand_partition(root_device) + except Exception: pass def get_disks(): - """Returns list of disks and their free space. + """Return list of disks and their free space. The primary source of information is UDisks' list of block devices. Information from df is used for free space available. @@ -136,8 +132,8 @@ def get_mounts(): def _get_disks_from_df(): """Return the list of disks and free space available using 'df'.""" try: - output = actions.superuser_run('storage', ['usage-info']) - except subprocess.CalledProcessError as exception: + output = privileged.usage_info() + except Exception as exception: logger.exception('Error getting disk information: %s', exception) return [] @@ -162,7 +158,7 @@ def _get_disks_from_df(): def get_filesystem_type(mount_point='/'): - """Returns the type of the filesystem mounted at mountpoint.""" + """Return the type of the filesystem mounted at mountpoint.""" for partition in psutil.disk_partitions(): if partition.mountpoint == mount_point: return partition.fstype @@ -204,19 +200,10 @@ def is_expandable(device): return False try: - output = actions.superuser_run('storage', - ['is-partition-expandable', device], - log_error=False) - except actions.ActionError: + return privileged.is_partition_expandable(device, _log_error=False) + except Exception: return False - return int(output.strip()) - - -def expand_partition(device): - """Expand a partition.""" - actions.superuser_run('storage', ['expand-partition', device]) - def format_bytes(size): """Return human readable disk size from bytes.""" diff --git a/plinth/modules/storage/forms.py b/plinth/modules/storage/forms.py index be419a827..232cdc9bb 100644 --- a/plinth/modules/storage/forms.py +++ b/plinth/modules/storage/forms.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Forms for directory selection. -""" +"""Forms for directory selection.""" import os @@ -9,11 +7,12 @@ from django import forms from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth.modules import storage from plinth.modules.samba import privileged as samba_privileged +from . import privileged + def get_available_samba_shares(): """Get available samba shares.""" @@ -40,6 +39,8 @@ def _is_app_enabled(app_id): class DirectoryValidator: + """Validation helper to check a directory.""" + username = None check_writable = False check_creatable = False @@ -48,6 +49,7 @@ class DirectoryValidator: def __init__(self, username=None, check_writable=None, check_creatable=None): + """Initialize the validator.""" if username is not None: self.username = username if check_writable is not None: @@ -60,29 +62,22 @@ class DirectoryValidator: if not value.startswith('/'): raise ValidationError(_('Invalid directory name.'), 'invalid') - command = ['validate-directory', '--path', value] - if self.check_creatable: - command.append('--check-creatable') - elif self.check_writable: - command.append('--check-writable') + try: + if not self.username: + raise ValueError('Invalid username for directory validator') - if self.username: - output = actions.run_as_user('storage', command, - become_user=self.username) - else: - output = actions.run('storage', command) - - if 'ValidationError' in output: - error_nr = int(output.strip().split()[1]) - if error_nr == 1: - raise ValidationError(_('Directory does not exist.'), - 'invalid') - elif error_nr == 2: - raise ValidationError(_('Path is not a directory.'), 'invalid') - elif error_nr == 3: + privileged.validate_directory(value, self.check_creatable, + self.check_writable, + _run_as_user=self.username) + except FileNotFoundError: + raise ValidationError(_('Directory does not exist.'), 'invalid') + except NotADirectoryError: + raise ValidationError(_('Path is not a directory.'), 'invalid') + except PermissionError as exception: + if exception.args[0] == 'read': raise ValidationError( _('Directory is not readable by the user.'), 'invalid') - elif error_nr == 4: + else: raise ValidationError( _('Directory is not writable by the user.'), 'invalid') diff --git a/actions/storage b/plinth/modules/storage/privileged.py old mode 100755 new mode 100644 similarity index 66% rename from actions/storage rename to plinth/modules/storage/privileged.py index ec682ec17..9138a7373 --- a/actions/storage +++ b/plinth/modules/storage/privileged.py @@ -1,85 +1,31 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for disks manager. -""" +"""Configure disks manager.""" -import argparse -import json import os import re import stat import subprocess -import sys from plinth import utils +from plinth.actions import privileged -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('setup', help='Configure storage after install') - - subparser = subparsers.add_parser( - 'is-partition-expandable', - help='Return whether a given partition can be expanded') - subparser.add_argument( - 'device', help='Partition for which check needs to be performed') - - subparser = subparsers.add_parser( - 'expand-partition', - help='Expand a partition to take adjacent free space') - subparser.add_argument('device', - help='Partition which needs to be resized') - subparser.add_argument( - '--mount-point', default='/', - help=('Mount point which the device is mounted. ' - 'Needed for btrfs filesystems')) - - subparser = subparsers.add_parser('mount', help='Mount a filesystem') - subparser.add_argument('--block-device', - help='Block device of the filesystem to mount') - - subparser = subparsers.add_parser('eject', help='Eject a storage device') - subparser.add_argument('device', help='Path of the device to eject') - - subparsers.add_parser('usage-info', - help='Get information about disk space usage') - - subparser = subparsers.add_parser('validate-directory', - help='Validate a directory') - subparser.add_argument('--path', help='Path of the directory', - required=True) - subparser.add_argument('--check-creatable', required=False, default=False, - action='store_true', - help='Check that the directory is creatable') - subparser.add_argument('--check-writable', required=False, default=False, - action='store_true', - help='Check that the directory is writable') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_is_partition_expandable(arguments): +@privileged +def is_partition_expandable(device: str) -> int: """Return a list of partitions that can be expanded.""" - _, _, free_space = _get_free_space(arguments.device) - print(free_space['size']) + _, _, free_space = _get_free_space(device) + return int(free_space['size']) -def subcommand_expand_partition(arguments): +@privileged +def expand_partition(device: str, mount_point: str = '/'): """Expand a partition to take adjacent free space.""" - device = arguments.device - mount_point = arguments.mount_point device, requested_partition, free_space = _get_free_space(device) if requested_partition['table_type'] == 'msdos' and \ int(requested_partition['number']) >= 5: - print('Expanding logical partitions currently unsupported', - file=sys.stderr) - sys.exit(4) + raise RuntimeError( + 'Expanding logical partitions currently unsupported') if requested_partition['table_type'] == 'gpt': _move_gpt_second_header(device) @@ -102,8 +48,7 @@ def _move_gpt_second_header(device): try: subprocess.run(command, check=True) except subprocess.CalledProcessError: - print('Error moving GPT second header to the end') - sys.exit(6) + raise RuntimeError('Error moving GPT second header to the end') def _resize_partition(device, requested_partition, free_space): @@ -127,8 +72,7 @@ def _resize_partition(device, requested_partition, free_space): subprocess.run(fallback_command, check=True, input=input_text.encode()) except subprocess.CalledProcessError as exception: - print('Error expanding partition:', exception, file=sys.stderr) - sys.exit(5) + raise RuntimeError(f'Error expanding partition: {exception}') def _resize_file_system(device, requested_partition, free_space, @@ -149,8 +93,7 @@ def _resize_ext4(device, requested_partition, _free_space, _mount_point): subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True) except subprocess.CalledProcessError as exception: - print('Error expanding filesystem:', exception, file=sys.stderr) - sys.exit(6) + raise RuntimeError(f'Error expanding filesystem: {exception}') def _resize_btrfs(_device, _requested_partition, _free_space, mount_point='/'): @@ -159,8 +102,7 @@ def _resize_btrfs(_device, _requested_partition, _free_space, mount_point='/'): command = ['btrfs', 'filesystem', 'resize', 'max', mount_point] subprocess.run(command, stdout=subprocess.DEVNULL, check=True) except subprocess.CalledProcessError as exception: - print('Error expanding filesystem:', exception, file=sys.stderr) - sys.exit(6) + raise RuntimeError(f'Error expanding filesystem: {exception}') def _get_free_space(device): @@ -172,21 +114,18 @@ def _get_free_space(device): requested_partition, free_spaces = \ _get_partitions_and_free_spaces(device, partition_number) except Exception as exception: - print('Error getting partition details: ', exception, file=sys.stderr) - sys.exit(2) + raise RuntimeError(f'Error getting partition details: {exception}') # Don't accept extended partitions for now if requested_partition['table_type'] == 'msdos' and \ int(requested_partition['number']) >= 5: - print('Expanding logical partitions currently unsupported', - file=sys.stderr) - sys.exit(3) + raise RuntimeError( + 'Expanding logical partitions currently unsupported') # Don't accept anything but btrfs and ext4 filesystems if requested_partition['type'] not in ('btrfs', 'ext4'): - print('Unsupported file system type: ', requested_partition['type'], - file=sys.stderr) - sys.exit(4) + raise RuntimeError( + f'Unsupported file system type: {requested_partition["type"]}') found_free_space = None for free_space in free_spaces: @@ -199,7 +138,7 @@ def _get_free_space(device): found_free_space = free_space if not found_free_space: - sys.exit(5) + raise RuntimeError('No free space available') return device, requested_partition, found_free_space @@ -218,8 +157,7 @@ def _get_root_device_and_partition_number(device): if not match: match = re.match(r'(.+[a-zA-Z])(\d+)$', device) if not match: - print('Invalid device, must be a partition', file=sys.stderr) - sys.exit(1) + raise ValueError('Invalid device, must be a partition') return match.group(1), match.group(2) @@ -263,7 +201,8 @@ def _interpret_unit(value): return int(value) -def subcommand_mount(arguments): +@privileged +def mount(block_device: str): """Mount a disk are root user. XXX: This is primarily to provide compatibility with older code that used @@ -276,22 +215,16 @@ def subcommand_mount(arguments): UDISKS_FILESYSTEM_SHARED=1 by writing a udev rule. """ - process = subprocess.run([ - 'udisksctl', 'mount', '--block-device', arguments.block_device, + subprocess.run([ + 'udisksctl', 'mount', '--block-device', block_device, '--no-user-interaction' - ], check=False) - sys.exit(process.returncode) + ], check=True) -def subcommand_eject(arguments): +@privileged +def eject(device_path: str) -> str: """Eject a device by its path.""" - device_path = arguments.device - try: - drive = eject_drive_of_device(device_path) - print(json.dumps(drive)) - except Exception as exception: - print(exception, file=sys.stderr) - sys.exit(1) + return _eject_drive_of_device(device_path) def _get_options(): @@ -302,7 +235,7 @@ def _get_options(): return options -def eject_drive_of_device(device_path): +def _eject_drive_of_device(device_path): """Eject a device after unmounting all of its partitions. Return the details (model, vendor) of drives ejected. @@ -327,10 +260,10 @@ def eject_drive_of_device(device_path): block_device = obj.get_block() drive_object_path = block_device.props.drive if drive_object_path != '/': - umount_all_filesystems_of_drive(drive_object_path) + _umount_all_filesystems_of_drive(drive_object_path) else: # Block device has not associated drive - umount_filesystem(obj.get_filesystem()) + _umount_filesystem(obj.get_filesystem()) # Eject the drive drive = client.get_drive_for_block(block_device) @@ -350,13 +283,13 @@ def eject_drive_of_device(device_path): return None -def umount_filesystem(filesystem): - """Unmount a filesystem """ +def _umount_filesystem(filesystem): + """Unmount a filesystem.""" if filesystem and filesystem.props.mount_points: filesystem.call_unmount_sync(_get_options()) -def umount_all_filesystems_of_drive(drive_object_path): +def _umount_all_filesystems_of_drive(drive_object_path): """Unmount all filesystems on block devices of a drive.""" udisks = utils.import_from_gi('UDisks', '2.0') client = udisks.Client.new_sync() @@ -367,10 +300,11 @@ def umount_all_filesystems_of_drive(drive_object_path): if not block_device or block_device.props.drive != drive_object_path: continue - umount_filesystem(obj.get_filesystem()) + _umount_filesystem(obj.get_filesystem()) -def subcommand_setup(_): +@privileged +def setup(): """Configure storage.""" # create udisks2 default mount directory mounts_directory = '/media/root' @@ -384,58 +318,43 @@ def subcommand_setup(_): os.chmod(mounts_directory, stats.st_mode | stat.S_IROTH | stat.S_IXOTH) -def subcommand_usage_info(_): +@privileged +def usage_info() -> str: """Get information about disk space usage.""" command = [ 'df', '--exclude-type=tmpfs', '--exclude-type=devtmpfs', '--block-size=1', '--output=source,fstype,size,used,avail,pcent,target' ] - subprocess.run(command, check=True) + return subprocess.check_output(command).decode() -def subcommand_validate_directory(arguments): - """Validate a directory""" +@privileged +def validate_directory(directory: str, check_creatable: bool, + check_writable: bool): + """Validate a directory.""" if os.geteuid() == 0: raise RuntimeError('You must not be root to run this command') - directory = arguments.path - def part_exists(path): - """Returns part of the path that exists.""" + """Return part of the path that exists.""" if not path or os.path.exists(path): return path return part_exists(os.path.dirname(path)) - if arguments.check_creatable: + if check_creatable: directory = part_exists(directory) if not directory: directory = '.' else: if not os.path.exists(directory): - # doesn't exist - print('ValidationError: 1') - return + raise FileNotFoundError if not os.path.isdir(directory): - # is not a directory - print('ValidationError: 2') - elif not os.access(directory, os.R_OK): - # is not readable - print('ValidationError: 3') - elif arguments.check_writable or arguments.check_creatable: + raise NotADirectoryError + + if not os.access(directory, os.R_OK): + raise PermissionError('read') + + if check_writable or check_creatable: if not os.access(directory, os.W_OK): - # is not writable - print('ValidationError: 4') - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() + raise PermissionError('write') diff --git a/plinth/modules/storage/tests/test_storage.py b/plinth/modules/storage/tests/test_storage.py index 4877ee81b..cb2672bd4 100644 --- a/plinth/modules/storage/tests/test_storage.py +++ b/plinth/modules/storage/tests/test_storage.py @@ -4,14 +4,17 @@ Test module for storage module operations. """ import contextlib -import os -import pathlib import re import subprocess import tempfile import pytest +from plinth.modules.storage import privileged + +pytestmark = pytest.mark.usefixtures('mock_privileged') +privileged_modules_to_mock = ['plinth.modules.storage.privileged'] + class Disk(): """Context manager to create/destroy a disk.""" @@ -255,8 +258,11 @@ def test_ext4_expansion(partition_table_type): def _assert_free_space(disk, partition_number, space=True): """Verify that free is available/not available after a partition.""" device = disk.get_partition_device(partition_number) - result = _check_action(['storage', 'is-partition-expandable', device]) - assert result == space + if space: + privileged.is_partition_expandable(device) + else: + with pytest.raises(RuntimeError): + privileged.is_partition_expandable(device) def _expand_partition(disk, partition_number, success=True): @@ -264,34 +270,15 @@ def _expand_partition(disk, partition_number, success=True): _assert_aligned(disk, partition_number) with disk.mount_partition(partition_number) as mount_point: device = disk.get_partition_device(partition_number) - result = _check_action([ - 'storage', 'expand-partition', device, '--mount-point', mount_point - ]) + if success: + privileged.expand_partition(device, mount_point) + else: + with pytest.raises(RuntimeError): + privileged.expand_partition(device, mount_point) - assert result == success _assert_aligned(disk, partition_number) -def _call_action(action_command, check=True, **kwargs): - """Call the action script.""" - test_directory = pathlib.Path(__file__).parent - top_directory = (test_directory / '..' / '..' / '..' / '..').resolve() - action_command[0] = top_directory / 'actions' / action_command[0] - kwargs['stdout'] = kwargs.get('stdout', subprocess.DEVNULL) - kwargs['stderr'] = kwargs.get('stderr', subprocess.DEVNULL) - env = dict(os.environ, PYTHONPATH=str(top_directory)) - return subprocess.run(action_command, env=env, check=check, **kwargs) - - -def _check_action(action_command): - """Return success/failure result of the action command.""" - try: - _call_action(action_command) - return True - except subprocess.CalledProcessError: - return False - - def _assert_aligned(disk, partition_number): """Test that partition is optimally aligned.""" subprocess.run([ @@ -319,43 +306,40 @@ def _assert_ext4_file_system_healthy(disk, partition_number): def _assert_validate_directory(path, error, check_writable=False, check_creatable=False): """Perform directory validation checks.""" - action_command = ['storage', 'validate-directory', '--path', path] - if check_writable: - action_command += ['--check-writable'] - if check_creatable: - action_command += ['--check-creatable'] - proc = _call_action(action_command, stderr=subprocess.PIPE, - stdout=subprocess.PIPE) - output = proc.stdout.decode() - if 'ValidationError' in output: - error_nr = output.strip().split()[1] - assert error_nr == error + if error: + match = None if not error.args else error.args[0] + with pytest.raises(error.__class__, match=match): + privileged.validate_directory(path, check_creatable, + check_writable) else: - assert output == error + privileged.validate_directory(path, check_creatable, check_writable) @pytest.mark.usefixtures('needs_not_root') -@pytest.mark.parametrize('path,error', [('/missing', '1'), - ('/etc/os-release', '2'), - ('/root', '3'), ('/', ''), - ('/etc/..', '')]) +@pytest.mark.parametrize('path,error', + [('/missing', FileNotFoundError()), + ('/etc/os-release', NotADirectoryError()), + ('/root', PermissionError('read')), ('/', None), + ('/etc/..', None)]) def test_validate_directory(path, error): """Test that directory validation returns expected output.""" _assert_validate_directory(path, error) @pytest.mark.usefixtures('needs_not_root') -@pytest.mark.parametrize('path,error', [('/', '4'), ('/tmp', '')]) +@pytest.mark.parametrize('path,error', [('/', PermissionError('write')), + ('/tmp', None)]) def test_validate_directory_writable(path, error): """Test that directory writable validation returns expected output.""" _assert_validate_directory(path, error, check_writable=True) @pytest.mark.usefixtures('needs_not_root') -@pytest.mark.parametrize('path,error', - [('/var/lib/plinth_storage_test_not_exists', '4'), - ('/tmp/plint_storage_test_not_exists', ''), - ('/var/../tmp/plint_storage_test_not_exists', '')]) +@pytest.mark.parametrize( + 'path,error', + [('/var/lib/plinth_storage_test_not_exists', PermissionError('write')), + ('/tmp/plint_storage_test_not_exists', None), + ('/var/../tmp/plint_storage_test_not_exists', None)]) def test_validate_directory_creatable(path, error): """Test that directory creatable validation returns expected output.""" _assert_validate_directory(path, error, check_creatable=True) diff --git a/plinth/modules/storage/udisks2.py b/plinth/modules/storage/udisks2.py index a98d985c8..9b536b40e 100644 --- a/plinth/modules/storage/udisks2.py +++ b/plinth/modules/storage/udisks2.py @@ -1,15 +1,14 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Handle disk operations using UDisk2 DBus API. -""" +"""Handle disk operations using UDisk2 DBus API.""" import logging import threading -from plinth import actions, cfg -from plinth.errors import ActionError +from plinth import cfg from plinth.utils import import_from_gi +from . import privileged + glib = import_from_gi('GLib', '2.0') gio = import_from_gi('Gio', '2.0') @@ -195,11 +194,8 @@ def _mount(object_path): logger.info('Auto-mounting device: %s %s', block_device.id, block_device.preferred_device) try: - actions.superuser_run( - 'storage', - ['mount', '--block-device', block_device.preferred_device], - log_error=False) - except ActionError as exception: + privileged.mount(block_device.preferred_device, _log_error=False) + except Exception as exception: parts = exception.args[2].split(':') if parts[1].strip() != 'GDBus.Error': raise diff --git a/plinth/modules/storage/views.py b/plinth/modules/storage/views.py index 749c27e8d..851929cb7 100644 --- a/plinth/modules/storage/views.py +++ b/plinth/modules/storage/views.py @@ -1,9 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Views for storage module. -""" +"""Views for storage module.""" -import json import logging import urllib.parse @@ -14,17 +11,17 @@ from django.urls import reverse from django.utils.translation import gettext as _ from django.views.decorators.http import require_POST -from plinth import actions, views -from plinth.errors import ActionError +from plinth import views from plinth.modules import storage -from . import get_error_message +from . import get_error_message, privileged logger = logging.getLogger(__name__) class StorageAppView(views.AppView): """Show storage information.""" + app_id = 'storage' template_name = 'storage.html' @@ -63,7 +60,7 @@ def expand(request): def expand_partition(request, device): """Expand the partition.""" try: - storage.expand_partition(device) + privileged.expand_partition(device) except Exception as exception: messages.error( request, @@ -83,8 +80,7 @@ def eject(request, device_path): device_path = urllib.parse.unquote(device_path) try: - drive = json.loads( - actions.superuser_run('storage', ['eject', device_path])) + drive = privileged.eject(device_path) if drive: messages.success( request, @@ -93,8 +89,8 @@ def eject(request, device_path): drive_model=drive['model'])) else: messages.success(request, _('Device can be safely unplugged.')) - except ActionError as exception: - message = get_error_message(exception.args[2]) + except Exception as exception: + message = get_error_message(exception.args[-2].decode()) # stdout logger.error('Error ejecting device - %s', message) messages.error( From 1dcbfce713da58f1a139b4735115d1e693c7f56f Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 10:49:02 -0700 Subject: [PATCH 68/90] users: Use privileged decorator for actions Tests: - Functional tests work (failing already) - DONE: Showing front page shortcuts according to user groups works - DONE: Only user who is party of syncthing group is shown syncthing - DONE: Admin users are always shown all the apps - DONE: Syncthing: - Not tested: When upgrading from version 2 or below, renaming group works - DONE: Syncthing is added to freedombox-share group - DONE: Initial setup of users app works - DONE: freedombox-share group is created - DONE: Retriving last admin user works - DONE: Last admin is not allowed to delete account - DONE: Creating a new user works - DONE: Password is set properly (user can login with 'su - user' after) - DONE: Incorrect confirmation password leads to error - DONE: Adding the user to groups works (edit page shows correct list of groups) - DONE: Editing a user works - DONE: User is renamed properly - DONE: Removing user from groups works - DONE: Adding user to new groups works - DONE: Providing incorrect auth password results in error message - DONE: Enabling/disabling account work (confirm with 'su - user'). See #2277. - DONE: Updating user password works - DONE: New password is set (confirm with 'su - user') - DONE: Providing incorrect auth password results in error message - DONE: Initial user account creation works - DONE: User account can be used (confirm with 'su - user') - DONE: User is added to admin group - DONE: Exception while getting SSH keys results in showing empty field - DONE: Removing a user works - DONE: Command provided in a message in users_firstboot.html works for deleting users. - DONE: If an admin users exists when running first wizard, list of admin users is shown. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/frontpage.py | 10 +- plinth/modules/syncthing/__init__.py | 5 +- plinth/modules/users/__init__.py | 28 +- plinth/modules/users/forms.py | 103 ++--- .../modules/users/privileged.py | 367 ++++++------------ .../users/templates/users_firstboot.html | 6 +- .../{test_actions.py => test_privileged.py} | 159 +++----- plinth/modules/users/tests/test_views.py | 28 +- plinth/modules/users/views.py | 27 +- plinth/tests/test_frontpage.py | 14 +- 10 files changed, 264 insertions(+), 483 deletions(-) rename actions/users => plinth/modules/users/privileged.py (52%) mode change 100755 => 100644 rename plinth/modules/users/tests/{test_actions.py => test_privileged.py} (70%) diff --git a/plinth/frontpage.py b/plinth/frontpage.py index 0fd7e8864..012ba3c75 100644 --- a/plinth/frontpage.py +++ b/plinth/frontpage.py @@ -1,15 +1,12 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Manage application shortcuts on front page. -""" +"""Manage application shortcuts on front page.""" import json import logging import pathlib from plinth import app, cfg - -from . import actions +from plinth.modules.users import privileged as users_privileged logger = logging.getLogger(__name__) @@ -116,8 +113,7 @@ class Shortcut(app.FollowerComponent): return cls._all_shortcuts # XXX: Turn this into an API call in users module and cache - output = actions.superuser_run('users', ['get-user-groups', username]) - user_groups = set(output.strip().split('\n')) + user_groups = set(users_privileged.get_user_groups(username)) if 'admin' in user_groups: # Admin has access to all services return cls._all_shortcuts diff --git a/plinth/modules/syncthing/__init__.py b/plinth/modules/syncthing/__init__.py index 770883447..fb1d53a64 100644 --- a/plinth/modules/syncthing/__init__.py +++ b/plinth/modules/syncthing/__init__.py @@ -10,6 +10,7 @@ from plinth.modules.apache.components import Webserver from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.modules.users import add_user_to_share_group +from plinth.modules.users import privileged as users_privileged from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages from plinth.utils import format_lazy @@ -119,9 +120,7 @@ class SyncthingApp(app_module.App): old_groupname = 'syncthing' new_groupname = 'syncthing-access' - actions.superuser_run( - 'users', - options=['rename-group', old_groupname, new_groupname]) + users_privileged.rename_group(old_groupname, new_groupname) from django.contrib.auth.models import Group Group.objects.filter(name=old_groupname).update(name=new_groupname) diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py index 4f4d18784..7176ac9a8 100644 --- a/plinth/modules/users/__init__.py +++ b/plinth/modules/users/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to manage users. -""" +"""FreedomBox app to manage users.""" import grp import subprocess @@ -15,6 +13,7 @@ from plinth import cfg, menu from plinth.daemon import Daemon from plinth.package import Packages +from . import privileged from .components import UsersAndGroups first_boot_steps = [ @@ -91,10 +90,10 @@ class UsersApp(app_module.App): """Install and configure the app.""" super().setup(old_version) if not old_version: - actions.superuser_run('users', ['first-setup']) + privileged.first_setup() - actions.superuser_run('users', ['setup']) - create_group('freedombox-share') + privileged.setup() + privileged.create_group('freedombox-share') def _diagnose_ldap_entry(search_item): @@ -114,21 +113,9 @@ def _diagnose_ldap_entry(search_item): return [testname, result] -def create_group(group): - """Add an LDAP group.""" - actions.superuser_run('users', options=['create-group', group]) - - -def remove_group(group): - """Remove an LDAP group.""" - actions.superuser_run('users', options=['remove-group', group]) - - def get_last_admin_user(): """If there is only one admin user return its name else return None.""" - output = actions.superuser_run('users', ['get-group-users', 'admin']) - admin_users = output.strip().split('\n') - + admin_users = privileged.get_group_users('admin') if len(admin_users) == 1 and admin_users[0]: return admin_users[0] @@ -142,7 +129,6 @@ def add_user_to_share_group(username, service=None): except KeyError: group_members = [] if username not in group_members: - actions.superuser_run( - 'users', ['add-user-to-group', username, 'freedombox-share']) + privileged.add_user_to_group(username, 'freedombox-share') if service: actions.superuser_run('service', ['try-restart', service]) diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py index 76747a9c2..64d379c45 100644 --- a/plinth/modules/users/forms.py +++ b/plinth/modules/users/forms.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later +"""Django forms for user management.""" import pwd import re @@ -16,13 +17,11 @@ from django.utils.translation import gettext_lazy import plinth.forms import plinth.modules.ssh.privileged as ssh_privileged -from plinth import actions -from plinth.errors import ActionError from plinth.modules import first_boot from plinth.modules.security import set_restricted_access from plinth.utils import is_user_admin -from . import get_last_admin_user +from . import get_last_admin_user, privileged from .components import UsersAndGroups @@ -74,11 +73,13 @@ USERNAME_FIELD = forms.CharField( class PasswordConfirmForm(forms.Form): """Password confirmation form.""" + confirm_password = forms.CharField( widget=forms.PasswordInput, label=gettext_lazy('Authorization Password')) def __init__(self, *args, **kwargs): + """Initialize form.""" super().__init__(*args, **kwargs) self.fields['confirm_password'].help_text = _( @@ -103,6 +104,7 @@ class CreateUserForm(ValidNewUsernameCheckMixin, Include options to add user to groups. """ + username = USERNAME_FIELD groups = forms.MultipleChoiceField( choices=UsersAndGroups.get_group_choices, @@ -120,6 +122,7 @@ class CreateUserForm(ValidNewUsernameCheckMixin, class Meta(UserCreationForm.Meta): """Metadata to control automatic form building.""" + fields = ('username', 'password1', 'password2', 'groups', 'language', 'confirm_password') @@ -143,14 +146,11 @@ class CreateUserForm(ValidNewUsernameCheckMixin, auth_username = self.request.user.username confirm_password = self.cleaned_data['confirm_password'] - process_input = '{0}\n{1}'.format(self.cleaned_data['password1'], - confirm_password).encode() try: - actions.superuser_run('users', [ - 'create-user', - user.get_username(), '--auth-user', auth_username - ], input=process_input) - except ActionError as error: + privileged.create_user(user.get_username(), + self.cleaned_data['password1'], + auth_username, confirm_password) + except Exception as error: messages.error( self.request, _('Creating LDAP user failed: {error}'.format( @@ -158,12 +158,10 @@ class CreateUserForm(ValidNewUsernameCheckMixin, for group in self.cleaned_data['groups']: try: - actions.superuser_run('users', [ - 'add-user-to-group', - user.get_username(), group, '--auth-user', - auth_username - ], input=confirm_password.encode()) - except ActionError as error: + privileged.add_user_to_group(user.get_username(), group, + auth_username, + confirm_password) + except Exception as error: messages.error( self.request, _('Failed to add new user to {group} group: {error}'). @@ -178,6 +176,7 @@ class CreateUserForm(ValidNewUsernameCheckMixin, class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, plinth.forms.LanguageSelectionFormMixin, forms.ModelForm): """When user info is changed, also updates LDAP user.""" + username = USERNAME_FIELD ssh_keys = forms.CharField( label=gettext_lazy('Authorized SSH Keys'), required=False, @@ -192,6 +191,7 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, class Meta: """Metadata to control automatic form building.""" + fields = ('username', 'groups', 'ssh_keys', 'language', 'is_active', 'confirm_password') model = User @@ -254,18 +254,13 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, user.save() self.save_m2m() - output = actions.superuser_run('users', - ['get-user-groups', self.username]) - old_groups = output.strip().split('\n') + old_groups = privileged.get_user_groups(self.username) old_groups = [group for group in old_groups if group] if self.username != user.get_username(): try: - actions.superuser_run( - 'users', - ['rename-user', self.username, - user.get_username()]) - except ActionError: + privileged.rename_user(self.username, user.get_username()) + except Exception: messages.error(self.request, _('Renaming LDAP user failed.')) @@ -273,24 +268,20 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, for old_group in old_groups: if old_group not in new_groups: try: - actions.superuser_run('users', [ - 'remove-user-from-group', - user.get_username(), old_group, '--auth-user', - auth_username - ], input=confirm_password.encode()) - except ActionError: + privileged.remove_user_from_group( + user.get_username(), old_group, auth_username, + confirm_password) + except Exception: messages.error(self.request, _('Failed to remove user from group.')) for new_group in new_groups: if new_group not in old_groups: try: - actions.superuser_run('users', [ - 'add-user-to-group', - user.get_username(), new_group, '--auth-user', - auth_username - ], input=confirm_password.encode()) - except ActionError: + privileged.add_user_to_group(user.get_username(), + new_group, auth_username, + confirm_password) + except Exception: messages.error(self.request, _('Failed to add user to group.')) @@ -308,14 +299,9 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, else: status = 'inactive' try: - actions.superuser_run('users', [ - 'set-user-status', - user.get_username(), - status, - '--auth-user', - auth_username, - ], input=confirm_password.encode()) - except ActionError: + privileged.set_user_status(user.get_username(), status, + auth_username, confirm_password) + except Exception: messages.error(self.request, _('Failed to change user status.')) @@ -352,15 +338,11 @@ class UserChangePasswordForm(PasswordConfirmForm, SetPasswordForm): user = super().save(commit) auth_username = self.request.user.username if commit: - process_input = '{0}\n{1}'.format( - self.cleaned_data['new_password1'], - self.cleaned_data['confirm_password']).encode() try: - actions.superuser_run('users', [ - 'set-user-password', - user.get_username(), '--auth-user', auth_username - ], input=process_input) - except ActionError: + privileged.set_user_password( + user.get_username(), self.cleaned_data['new_password1'], + auth_username, self.cleaned_data['confirm_password']) + except Exception: messages.error(self.request, _('Changing LDAP user password failed.')) @@ -369,6 +351,7 @@ class UserChangePasswordForm(PasswordConfirmForm, SetPasswordForm): class FirstBootForm(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm): """User module first boot step: create a new admin user.""" + username = USERNAME_FIELD def __init__(self, *args, **kwargs): @@ -383,23 +366,17 @@ class FirstBootForm(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm): first_boot.mark_step_done('users_firstboot') try: - actions.superuser_run( - 'users', - ['create-user', - user.get_username(), '--auth-user', ''], - input=self.cleaned_data['password1'].encode()) - except ActionError as error: + privileged.create_user(user.get_username(), + self.cleaned_data['password1']) + except Exception as error: messages.error( self.request, _('Creating LDAP user failed: {error}'.format( error=error))) try: - actions.superuser_run( - 'users', - ['add-user-to-group', - user.get_username(), 'admin']) - except ActionError as error: + privileged.add_user_to_group(user.get_username(), 'admin') + except Exception as error: messages.error( self.request, _('Failed to add new user to admin group: {error}'.format( diff --git a/actions/users b/plinth/modules/users/privileged.py old mode 100755 new mode 100644 similarity index 52% rename from actions/users rename to plinth/modules/users/privileged.py index 759b847eb..099e24c44 --- a/actions/users +++ b/plinth/modules/users/privileged.py @@ -1,142 +1,53 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Configuration helper for the LDAP user directory -""" +"""Configuration helper for the LDAP user directory.""" -import argparse import logging import os import re import shutil import subprocess -import sys +from typing import Optional import augeas from plinth import action_utils, utils +from plinth.actions import privileged INPUT_LINES = None ACCESS_CONF = '/etc/security/access.conf' LDAPSCRIPTS_CONF = '/etc/ldapscripts/freedombox-ldapscripts.conf' -def parse_arguments(): - """Return parsed command line arguments as dictionary""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('first-setup', help='Perform initial setup of LDAP') - subparsers.add_parser('setup', help='Setup LDAP') - - subparser = subparsers.add_parser('create-user', - help='Create an LDAP user') - subparser.add_argument('username', help='Name of the LDAP user to create') - subparser.add_argument('--auth-user', required=True) - - subparser = subparsers.add_parser('remove-user', - help='Delete an LDAP user') - subparser.add_argument( - 'username', help='Name of the LDAP user to delete. If the username is ' - 'the last admin user, a password should be provided through STDIN.') - - subparser = subparsers.add_parser('rename-user', - help='Rename an LDAP user') - subparser.add_argument('oldusername', help='Old name of the LDAP user') - subparser.add_argument('newusername', help='New name of the LDAP user') - - subparser = subparsers.add_parser('set-user-password', - help='Set the password of an LDAP user') - subparser.add_argument( - 'username', help='Name of the LDAP user to set the password for') - subparser.add_argument('--auth-user', required=True) - - subparser = subparsers.add_parser('create-group', - help='Create an LDAP group') - subparser.add_argument('groupname', - help='Name of the LDAP group to create') - - subparser = subparsers.add_parser('rename-group', - help='Rename an LDAP group') - subparser.add_argument('old_groupname', - help='Name of the LDAP group to rename') - subparser.add_argument('new_groupname', help='Name of the new LDAP group') - - subparser = subparsers.add_parser('remove-group', - help='Delete an LDAP group') - subparser.add_argument('groupname', - help='Name of the LDAP group to delete') - - subparser = subparsers.add_parser( - 'get-user-groups', help='Get all the LDAP groups for an LDAP user') - subparser.add_argument('username', - help='LDAP user to retrieve the groups for') - - subparser = subparsers.add_parser('add-user-to-group', - help='Add an LDAP user to an LDAP group') - subparser.add_argument('username', help='LDAP user to add to group') - subparser.add_argument('groupname', help='LDAP group to add the user to') - subparser.add_argument('--auth-user', required=False) - - subparser = subparsers.add_parser('set-user-status', - help='Set user as active or inactive') - subparser.add_argument('username', help='User to change status') - subparser.add_argument('status', choices=['active', 'inactive'], - help='New status of the user') - subparser.add_argument('--auth-user', required=True) - - subparser = subparsers.add_parser( - 'remove-user-from-group', - help='Remove an LDAP user from an LDAP group') - subparser.add_argument('username', help='LDAP user to remove from group') - subparser.add_argument('groupname', - help='LDAP group to remove the user from') - subparser.add_argument('--auth-user', required=False) - - help_get_group_users = 'Get the list of all users in an LDAP group' - subparser = subparsers.add_parser('get-group-users', - help=help_get_group_users) - subparser.add_argument( - 'groupname', help='name of the LDAP group to get the ' - 'list of users') - - subparsers.required = True - return parser.parse_args() - - -def validate_user(username, must_be_admin=True): +def _validate_user(username, password, must_be_admin=True): """Validate a user.""" if must_be_admin: - admins = get_admin_users() + admins = _get_admin_users() if not admins: # any user is valid return if not username: - msg = 'Argument --auth-user is required' - raise argparse.ArgumentTypeError(msg) + raise PermissionError('Authentication user is required') if username not in admins: - msg = '"{}" is not authorized to perform this action'.format( - username) - raise argparse.ArgumentTypeError(msg) + msg = f'"{username}" is not authorized to perform this action' + raise PermissionError(msg) if not username: - msg = 'Argument --auth-user is required' - raise argparse.ArgumentTypeError(msg) + raise PermissionError('Authentication user is required') - validate_password(username) + _validate_password(username, password) -def validate_password(username): +def _validate_password(username, password): """Raise an error if the user password is invalid.""" - password = read_password(last=True) if not utils.is_authenticated_user(username, password): - raise argparse.ArgumentTypeError("Invalid credentials") + raise PermissionError('Invalid credentials') -def subcommand_first_setup(_): +@privileged +def first_setup(): """Perform initial setup of LDAP.""" # Avoid reconfiguration of slapd during module upgrades, because # this will move the existing database. @@ -147,19 +58,20 @@ def subcommand_first_setup(_): action_utils.dpkg_reconfigure('slapd', {'domain': 'thisbox'}) -def subcommand_setup(_): +@privileged +def setup(): """Setup LDAP.""" # Update pam configs for access and mkhomedir. subprocess.run(['pam-auth-update', '--package'], check=True) - configure_ldapscripts() + _configure_ldapscripts() - configure_ldap_authentication() + _configure_ldap_authentication() - configure_ldap_structure() + _configure_ldap_structure() -def configure_ldap_authentication(): +def _configure_ldap_authentication(): """Configure LDAP authentication.""" action_utils.dpkg_reconfigure( 'nslcd', { @@ -179,18 +91,18 @@ def configure_ldap_authentication(): action_utils.service_start('nslcd') -def configure_ldap_structure(): +def _configure_ldap_structure(): """Configure LDAP basic structure.""" was_running = action_utils.service_is_running('slapd') if not was_running: action_utils.service_start('slapd') - setup_admin() - create_organizational_unit('users') - create_organizational_unit('groups') + _setup_admin() + _create_organizational_unit('users') + _create_organizational_unit('groups') -def create_organizational_unit(unit): +def _create_organizational_unit(unit): """Create an organizational unit in LDAP.""" distinguished_name = 'ou={unit},dc=thisbox'.format(unit=unit) try: @@ -210,7 +122,7 @@ ou: {unit}'''.format(unit=unit) check=True) -def setup_admin(): +def _setup_admin(): """Remove LDAP admin password and Allow root to modify the users.""" process = subprocess.run([ 'ldapsearch', '-Q', '-L', '-L', '-L', '-Y', 'EXTERNAL', '-H', @@ -243,7 +155,7 @@ olcRootDN: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth ''') -def configure_ldapscripts(): +def _configure_ldapscripts(): """Set the configuration used by ldapscripts for later user management.""" # modify a copy of the config file shutil.copy('/etc/ldapscripts/ldapscripts.conf', LDAPSCRIPTS_CONF) @@ -266,7 +178,7 @@ def configure_ldapscripts(): aug.save() -def get_samba_users(): +def _get_samba_users(): """Get users from the Samba user database.""" # 'pdbedit -L' is better for listing users but is installed only with samba stdout = subprocess.check_output( @@ -274,14 +186,14 @@ def get_samba_users(): return re.findall(r'USER_(.*)\\0', stdout) -def delete_samba_user(username): +def _delete_samba_user(username): """Delete a Samba user.""" - if username in get_samba_users(): + if username in _get_samba_users(): subprocess.check_call(['smbpasswd', '-x', username]) - disconnect_samba_user(username) + _disconnect_samba_user(username) -def disconnect_samba_user(username): +def _disconnect_samba_user(username): """Disconnect a Samba user.""" try: subprocess.check_call(['pkill', '-U', username, 'smbd']) @@ -290,84 +202,63 @@ def disconnect_samba_user(username): raise -def get_input_lines(): - """Return list of input lines from stdin.""" - global INPUT_LINES - if INPUT_LINES is None: - INPUT_LINES = [line.strip() for line in sys.stdin] - return INPUT_LINES - - -def read_password(last=False): - """Return the password. - - Set last=True to read password from last line of the input. - - """ - line = -1 if last else 0 - return get_input_lines()[line] - - -def subcommand_create_user(arguments): +@privileged +def create_user(username: str, password: str, auth_user: Optional[str] = None, + auth_password: Optional[str] = None): """Create an LDAP user, set password and flush cache.""" - username = arguments.username - auth_user = arguments.auth_user - - validate_user(auth_user) + _validate_user(auth_user, auth_password) _run(['ldapadduser', username, 'users']) - password = read_password() - set_user_password(username, password) - flush_cache() - set_samba_user(username, password) + _set_user_password(username, password) + _flush_cache() + _set_samba_user(username, password) -def subcommand_remove_user(arguments): +@privileged +def remove_user(username: str, password: Optional[str] = None): """Remove an LDAP user.""" - username = arguments.username - groups = get_user_groups(username) + groups = _get_user_groups(username) # require authentication if the user is last admin user - if get_group_users('admin') == [username]: - validate_password(username) + if _get_group_users('admin') == [username]: + _validate_password(username, password) - delete_samba_user(username) + _delete_samba_user(username) for group in groups: - remove_user_from_group(username, group) + _remove_user_from_group(username, group) _run(['ldapdeleteuser', username]) - flush_cache() + _flush_cache() -def subcommand_rename_user(arguments): +@privileged +def rename_user(old_username: str, new_username: str): """Rename an LDAP user.""" - old_username = arguments.oldusername - new_username = arguments.newusername - groups = get_user_groups(old_username) + groups = _get_user_groups(old_username) - delete_samba_user(old_username) + _delete_samba_user(old_username) for group in groups: - remove_user_from_group(old_username, group) + _remove_user_from_group(old_username, group) _run(['ldaprenameuser', old_username, new_username]) for group in groups: - add_user_to_group(new_username, group) + _add_user_to_group(new_username, group) - flush_cache() + _flush_cache() -def set_user_password(username, password): +def _set_user_password(username, password): """Set a user's password.""" process = _run(['slappasswd', '-s', password], stdout=subprocess.PIPE) password = process.stdout.decode().strip() _run(['ldapsetpasswd', username, password]) -def set_samba_user(username, password): +def _set_samba_user(username, password): """Insert a user to the Samba database. If a user already exists, update password. @@ -379,24 +270,21 @@ def set_samba_user(username, password): raise RuntimeError('Unable to add Samba user: ', proc.stderr) -def subcommand_set_user_password(arguments): +@privileged +def set_user_password(username: str, password: str, auth_user: str, + auth_password: str): """Set a user's password.""" - username = arguments.username - auth_user = arguments.auth_user - must_be_admin = username != auth_user - validate_user(auth_user, must_be_admin=must_be_admin) + _validate_user(auth_user, auth_password, must_be_admin=must_be_admin) - password = read_password() - set_user_password(username, password) - set_samba_user(username, password) + _set_user_password(username, password) + _set_samba_user(username, password) -def get_admin_users(): - """Returns list of members in the admin group. - - Raises an error if the slapd service is not running. +def _get_admin_users(): + """Return list of members in the admin group. + Raise an error if the slapd service is not running. """ admin_users = [] @@ -420,8 +308,8 @@ def get_admin_users(): return admin_users -def get_group_users(groupname): - """Returns list of members in the group.""" +def _get_group_users(groupname): + """Return list of members in the group.""" try: process = _run(['ldapgid', '-P', groupname], stdout=subprocess.PIPE) except subprocess.CalledProcessError: @@ -435,10 +323,11 @@ def get_group_users(groupname): return users -def get_user_groups(username): - """Returns only the supplementary groups of the given user. +def _get_user_groups(username): + """Return only the supplementary groups of the given user. - Exclude the 'users' primary group from the returned list.""" + Exclude the 'users' primary group from the returned list. + """ process = _run(['ldapid', username], stdout=subprocess.PIPE, check=False) output = process.stdout.decode().strip() if output: @@ -460,121 +349,119 @@ def get_user_groups(username): return [] -def subcommand_get_user_groups(arguments): +@privileged +def get_user_groups(username: str) -> list[str]: """Return list of a given user's groups.""" - groups = get_user_groups(arguments.username) - if groups: - print(*groups, sep='\n') + return _get_user_groups(username) -def group_exists(groupname): +def _group_exists(groupname): """Return whether a group already exits.""" process = _run(['ldapgid', groupname], check=False) return process.returncode == 0 -def create_group(groupname): +def _create_group(groupname): """Add an LDAP group.""" - if not group_exists(groupname): + if not _group_exists(groupname): _run(['ldapaddgroup', groupname]) -def subcommand_create_group(arguments): +@privileged +def create_group(groupname: str): """Add an LDAP group.""" - create_group(arguments.groupname) - flush_cache() + _create_group(groupname) + _flush_cache() -def subcommand_rename_group(arguments): +@privileged +def rename_group(old_groupname: str, new_groupname: str): """Rename an LDAP group. Skip if the group to rename from doesn't exist. """ - old_groupname = arguments.old_groupname - new_groupname = arguments.new_groupname - if old_groupname == 'admin' or new_groupname == 'admin': - raise argparse.ArgumentTypeError('Can\'t rename the group "admin"') + raise ValueError('Can\'t rename the group "admin"') - if group_exists(old_groupname): + if _group_exists(old_groupname): _run(['ldaprenamegroup', old_groupname, new_groupname]) - flush_cache() + _flush_cache() -def subcommand_remove_group(arguments): +@privileged +def remove_group(groupname: str): """Remove an LDAP group.""" - groupname = arguments.groupname - if groupname == 'admin': - raise argparse.ArgumentTypeError("Can't remove the group 'admin'") + raise ValueError("Can't remove the group 'admin'") - if group_exists(groupname): + if _group_exists(groupname): _run(['ldapdeletegroup', groupname]) - flush_cache() + _flush_cache() -def add_user_to_group(username, groupname): +def _add_user_to_group(username, groupname): """Add an LDAP user to an LDAP group.""" - create_group(groupname) + _create_group(groupname) _run(['ldapaddusertogroup', username, groupname]) -def subcommand_add_user_to_group(arguments): +@privileged +def add_user_to_group(username: str, groupname: str, + auth_user: Optional[str] = None, + auth_password: Optional[str] = None): """Add an LDAP user to an LDAP group.""" - groupname = arguments.groupname - if groupname == 'admin': - validate_user(arguments.auth_user) + _validate_user(auth_user, auth_password) - add_user_to_group(arguments.username, groupname) - flush_cache() + _add_user_to_group(username, groupname) + _flush_cache() -def remove_user_from_group(username, groupname): +def _remove_user_from_group(username, groupname): """Remove an LDAP user from an LDAP group.""" _run(['ldapdeleteuserfromgroup', username, groupname]) -def subcommand_remove_user_from_group(arguments): +@privileged +def remove_user_from_group(username: str, groupname: str, auth_user: str, + auth_password: str): """Remove an LDAP user from an LDAP group.""" - username = arguments.username - groupname = arguments.groupname - if groupname == 'admin': - validate_user(arguments.auth_user) + _validate_user(auth_user, auth_password) - remove_user_from_group(username, groupname) - flush_cache() + _remove_user_from_group(username, groupname) + _flush_cache() if groupname == 'freedombox-share': - disconnect_samba_user(username) + _disconnect_samba_user(username) -def subcommand_get_group_users(arguments): +@privileged +def get_group_users(group_name: str) -> list[str]: """Get the list of users of an LDAP group.""" - for user in get_group_users(arguments.groupname): - print(user) + return _get_group_users(group_name) -def subcommand_set_user_status(arguments): +@privileged +def set_user_status(username: str, status: str, auth_user: str, + auth_password: str): """Set the status of the user.""" - username = arguments.username - status = arguments.status - auth_user = arguments.auth_user + if status not in ('active', 'inactive'): + raise ValueError('Invalid status') - validate_user(auth_user) + _validate_user(auth_user, auth_password) if status == 'active': flag = '-e' else: flag = '-d' - if username in get_samba_users(): + if username in _get_samba_users(): subprocess.check_call(['smbpasswd', flag, username]) if status == 'inactive': - disconnect_samba_user(username) + _disconnect_samba_user(username) -def flush_cache(): +def _flush_cache(): """Flush nscd and apache2 cache.""" _run(['nscd', '--invalidate=passwd']) _run(['nscd', '--invalidate=group']) @@ -587,17 +474,3 @@ def _run(arguments, check=True, **kwargs): kwargs['stdout'] = kwargs.get('stdout', subprocess.DEVNULL) kwargs['stderr'] = kwargs.get('stderr', subprocess.DEVNULL) return subprocess.run(arguments, env=env, check=check, **kwargs) - - -def main(): - """Parse arguments and perform all duties""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/users/templates/users_firstboot.html b/plinth/modules/users/templates/users_firstboot.html index 0802a12d9..0e3537f93 100644 --- a/plinth/modules/users/templates/users_firstboot.html +++ b/plinth/modules/users/templates/users_firstboot.html @@ -50,9 +50,9 @@ {% blocktrans trimmed %} Delete these accounts from command line and refresh the page to create an account that is usable with {{ box_name }}. On the command line run - the command 'echo "{password}" | /usr/share/plinth/actions/users - remove-user {username}'. If an account is already usable with - {{ box_name }}, skip this step. + the command "echo '{"args": ["USERNAME", "PASSWORD"], "kwargs": {}}' | + sudo /usr/share/plinth/actions/actions users remove_user". If an + account is already usable with {{ box_name }}, skip this step. {% endblocktrans %}

diff --git a/plinth/modules/users/tests/test_actions.py b/plinth/modules/users/tests/test_privileged.py similarity index 70% rename from plinth/modules/users/tests/test_actions.py rename to plinth/modules/users/tests/test_privileged.py index 832077d4e..54abf15e8 100644 --- a/plinth/modules/users/tests/test_actions.py +++ b/plinth/modules/users/tests/test_privileged.py @@ -1,4 +1,3 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later """ Test module to exercise user actions. @@ -6,7 +5,6 @@ Test module to exercise user actions. it is recommended to run this module with root privileges in a virtual machine. """ -import pathlib import random import re import string @@ -15,9 +13,15 @@ import subprocess import pytest from plinth import action_utils -from plinth.modules import security +from plinth.modules.security import privileged as security_privileged +from plinth.modules.users import privileged from plinth.tests import config as test_config +pytestmark = pytest.mark.usefixtures('mock_privileged') +privileged_modules_to_mock = [ + 'plinth.modules.users.privileged', 'plinth.modules.security.privileged' +] + _cleanup_users = None _cleanup_groups = None @@ -48,13 +52,6 @@ def _random_string(length=8): [random.choice(string.ascii_lowercase) for _ in range(length)]) -def _is_exit_zero(args): - """Return whether a command gave exit code zero""" - process = subprocess.run(args, stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, check=False) - return process.returncode == 0 - - def _get_password_hash(username): """Query and return the password hash of the given LDAP username""" query = [ @@ -90,21 +87,14 @@ def _try_login_to_ssh(username, password, returncode=0): return process.returncode == returncode -def _action_file(): - """Return the path to the 'users' actions file.""" - current_directory = pathlib.Path(__file__).parent - return str(current_directory / '..' / '..' / '..' / '..' / 'actions' / - 'users') - - @pytest.fixture(name='disable_restricted_access', autouse=True) def fixture_disable_restricted_access(needs_root, load_cfg): """Disable console login restrictions.""" - restricted_access = security.get_restricted_access_enabled() + restricted_access = security_privileged.get_restricted_access_enabled() if restricted_access: - security.set_restricted_access(False) + security_privileged.disable_restricted_access() yield - security.set_restricted_access(True) + security_privileged.enable_restricted_access() else: yield @@ -135,14 +125,7 @@ def fixture_auto_cleanup_users_groups(needs_root, load_cfg): pass for group in _cleanup_groups: - _delete_group(group) - - -def _call_action(arguments, check=True, **kwargs): - """Call the action script.""" - kwargs['stdout'] = kwargs.get('stdout', subprocess.PIPE) - kwargs['stderr'] = kwargs.get('stderr', subprocess.PIPE) - return subprocess.run([_action_file()] + arguments, check=check, **kwargs) + privileged.remove_group(group) def _create_user(username=None, groups=None): @@ -151,16 +134,13 @@ def _create_user(username=None, groups=None): password = username + '_passwd' admin_user, admin_password = _get_admin_user_password() - process_input = "{0}\n{1}".format(password, admin_password).encode() - _call_action(['create-user', '--auth-user', admin_user, username], - input=process_input) + privileged.create_user(username, password, admin_user, admin_password) if groups: for group in groups: admin_user, admin_password = _get_admin_user_password() - _call_action([ - 'add-user-to-group', '--auth-user', admin_user, username, group - ], input=admin_password.encode()) + privileged.add_user_to_group(username, group, admin_user, + admin_password) if group != 'admin': _cleanup_groups.add(group) @@ -170,11 +150,11 @@ def _create_user(username=None, groups=None): def _delete_user(username): """Utility to delete an LDAP and Samba user""" - process_input = None - if _get_group_users('admin') == [username]: + admin_password = None + if privileged.get_group_users('admin') == [username]: _, admin_password = _get_admin_user_password() - process_input = admin_password.encode() - _call_action(['remove-user', username], input=process_input) + + privileged.remove_user(username, admin_password) def _create_admin_if_does_not_exist(): @@ -186,8 +166,7 @@ def _create_admin_if_does_not_exist(): def _get_admin_user_password(): """Return an admin username and password.""" - - admin_users = _get_group_users('admin') + admin_users = privileged.get_group_users('admin') if not admin_users: return ('', '') @@ -205,36 +184,20 @@ def _rename_user(old_username, new_username=None): """Rename a user.""" new_username = new_username or _random_string() - _call_action(['rename-user', old_username, new_username]) + privileged.rename_user(old_username, new_username) _cleanup_users.remove(old_username) _cleanup_users.add(new_username) return new_username -def _get_group_users(group): - """Return the list of members in a group.""" - process = _call_action(['get-group-users', group]) - return process.stdout.decode().split() - - -def _get_user_groups(username): - """Return the list of groups for a user.""" - process = _call_action(['get-user-groups', username]) - return process.stdout.decode().split() - - def _create_group(groupname=None): groupname = groupname or _random_string() - _call_action(['create-group', groupname]) + privileged.create_group(groupname) if groupname != 'admin': _cleanup_groups.add(groupname) return groupname -def _delete_group(groupname): - _call_action(['remove-group', groupname]) - - def test_create_user(): """Test whether creating a new user works.""" _create_admin_if_does_not_exist() @@ -256,9 +219,8 @@ def test_change_user_password(): old_password_hash = _get_password_hash(username) new_password = 'pass $123' - process_input = "{0}\n{1}".format(new_password, admin_password).encode() - _call_action(['set-user-password', username, '--auth-user', admin_user], - input=process_input) + privileged.set_user_password(username, new_password, admin_user, + admin_password) new_password_hash = _get_password_hash(username) assert old_password_hash != new_password_hash @@ -277,9 +239,8 @@ def test_change_password_as_non_admin_user(): old_password_hash = _get_password_hash(username) new_password = 'pass $123' - process_input = "{0}\n{1}".format(new_password, old_password).encode() - _call_action(['set-user-password', username, '--auth-user', username], - input=process_input) + privileged.set_user_password(username, new_password, username, + old_password) new_password_hash = _get_password_hash(username) assert old_password_hash != new_password_hash @@ -298,11 +259,9 @@ def test_change_other_users_password_as_non_admin(): username2, _ = _create_user() new_password = 'pass $123' - process_input = "{0}\n{1}".format(new_password, password1).encode() with pytest.raises(subprocess.CalledProcessError): - _call_action( - ['set-user-password', username2, '--auth-user', username1], - input=process_input) + privileged.set_user_password(username2, new_password, username1, + password1) def test_set_password_for_non_existent_user(): @@ -313,11 +272,9 @@ def test_set_password_for_non_existent_user(): non_existent_user = _random_string() fake_password = _random_string() - process_input = "{0}\n{1}".format(fake_password, admin_password).encode() with pytest.raises(subprocess.CalledProcessError): - _call_action([ - 'set-user-password', non_existent_user, '--auth-user', admin_user - ], input=process_input) + privileged.set_user_password(non_existent_user, fake_password, + admin_user, admin_password) def test_rename_user(): @@ -325,15 +282,15 @@ def test_rename_user(): _create_admin_if_does_not_exist() old_username, password = _create_user(groups=['admin', _random_string()]) - old_groups = _get_user_groups(old_username) + old_groups = privileged.get_user_groups(old_username) new_username = _rename_user(old_username) assert _try_login_to_ssh(new_username, password) assert _try_login_to_ssh(old_username, password, returncode=5) assert old_username not in _get_samba_users() - new_groups = _get_user_groups(new_username) - old_users_groups = _get_user_groups(old_username) + new_groups = privileged.get_user_groups(new_username) + old_users_groups = privileged.get_user_groups(old_username) assert not old_users_groups # empty assert old_groups == new_groups @@ -357,11 +314,12 @@ def test_delete_user(): username, password = _create_user(groups=[_random_string()]) _delete_user(username) - groups_after = _get_user_groups(username) + groups_after = privileged.get_user_groups(username) assert not groups_after # User gets removed from all groups # User account cannot be found after deletion - assert not _is_exit_zero(['ldapid', username]) + with pytest.raises(subprocess.CalledProcessError): + subprocess.run(['ldapid', username], check=True) # Deleted user cannot login to ssh assert _try_login_to_ssh(username, password, returncode=5) @@ -373,7 +331,7 @@ def test_delete_non_existent_user(): """Deleting a non-existent user should fail.""" non_existent_user = _random_string() with pytest.raises(subprocess.CalledProcessError): - _call_action(['delete-user', non_existent_user]) + privileged.remove_user(non_existent_user) def test_groups(): @@ -381,16 +339,18 @@ def test_groups(): groupname = _random_string() _create_group(groupname) - assert _is_exit_zero(['ldapgid', groupname]) + with pytest.raises(subprocess.CalledProcessError): + subprocess.run(['ldapgid', groupname], check=True) # create-group is idempotent - assert _is_exit_zero([_action_file(), 'create-group', groupname]) + privileged.create_group(groupname) - _delete_group(groupname) - assert not _is_exit_zero(['ldapgid', groupname]) + privileged.remove_group(groupname) + with pytest.raises(subprocess.CalledProcessError): + subprocess.run(['ldapgid', groupname], check=True) # delete-group is idempotent - assert _is_exit_zero([_action_file(), 'remove-group', groupname]) + privileged.remove_group(groupname) def test_delete_admin_group_fails(): @@ -398,7 +358,8 @@ def test_delete_admin_group_fails(): groupname = 'admin' _create_group('admin') - assert not _is_exit_zero([_action_file(), 'remove-group', groupname]) + with pytest.raises(ValueError): + privileged.remove_group(groupname) def test_user_group_interactions(): @@ -408,48 +369,38 @@ def test_user_group_interactions(): group1 = _random_string() user1, _ = _create_user(groups=[group1]) - assert [group1] == _get_user_groups(user1) + assert [group1] == privileged.get_user_groups(user1) # add-user-to-group is not idempotent with pytest.raises(subprocess.CalledProcessError): - _call_action( - ['add-user-to-group', '--auth-user', admin_user, user1, group1], - input=admin_password.encode()) + privileged.add_user_to_group(user1, group1, admin_user, admin_password) # The same user can be added to other new groups group2 = _random_string() _create_group(group2) - _call_action( - ['add-user-to-group', '--auth-user', admin_user, user1, group2], - input=admin_password.encode()) + privileged.add_user_to_group(user1, group2, admin_user, admin_password) # Adding a user to a non-existent group creates the group group3 = _random_string() - _call_action( - ['add-user-to-group', '--auth-user', admin_user, user1, group3], - input=admin_password.encode()) + privileged.add_user_to_group(user1, group3, admin_user, admin_password) _cleanup_groups.add(group3) # The expected groups got created and the user is part of them. expected_groups = [group1, group2, group3] - assert expected_groups == _get_user_groups(user1) + assert expected_groups == privileged.get_user_groups(user1) # Remove user from group group_to_remove_from = random.choice(expected_groups) - _call_action([ - 'remove-user-from-group', '--auth-user', admin_user, user1, - group_to_remove_from - ], input=admin_password.encode()) + privileged.remove_user_from_group(user1, group_to_remove_from, admin_user, + admin_password) # User is no longer in the group that they're removed from expected_groups.remove(group_to_remove_from) - assert expected_groups == _get_user_groups(user1) + assert expected_groups == privileged.get_user_groups(user1) # User cannot be removed from a group that they're not part of random_group = _random_string() _create_group(random_group) with pytest.raises(subprocess.CalledProcessError): - _call_action([ - 'remove-user-from-group', '--auth-user', admin_user, user1, - random_group - ], input=admin_password.encode()) + privileged.remove_user_from_group(user1, random_group, admin_user, + admin_password) diff --git a/plinth/modules/users/tests/test_views.py b/plinth/modules/users/tests/test_views.py index 467604990..a622c7a58 100644 --- a/plinth/modules/users/tests/test_views.py +++ b/plinth/modules/users/tests/test_views.py @@ -31,18 +31,6 @@ def fixture_users_urls(): yield -def action_run(action, options, **kwargs): - """Action return values.""" - if action == 'users' and options == ['get-group-users', 'admin']: - return 'admin' - if action == 'ssh' and options[:2] == ['get-keys', '--username']: - return '' - if action == 'users' and options == ['get-user-groups', 'tester']: - return '' - - return None - - @pytest.fixture(autouse=True) def module_patch(): """Patch users module.""" @@ -54,8 +42,20 @@ def module_patch(): UsersAndGroups('users-and-groups-minetest', reserved_usernames=['debian-minetest']) - with patch('pwd.getpwall', return_value=pwd_users),\ - patch('plinth.actions.superuser_run', side_effect=action_run): + privileged = 'plinth.modules.users.privileged' + with patch('pwd.getpwall', return_value=pwd_users), \ + patch(f'{privileged}.create_user'), \ + patch(f'{privileged}.add_user_to_group'), \ + patch(f'{privileged}.set_user_password'), \ + patch(f'{privileged}.set_user_status'), \ + patch(f'{privileged}.rename_user'), \ + patch(f'{privileged}.get_group_users') as get_group_users, \ + patch('plinth.modules.ssh.privileged.set_keys'), \ + patch('plinth.modules.ssh.privileged.get_keys') as get_keys, \ + patch(f'{privileged}.get_user_groups') as get_user_groups: + get_group_users.return_value = ['admin'] + get_keys.return_value = [] + get_user_groups.return_value = [] yield diff --git a/plinth/modules/users/views.py b/plinth/modules/users/views.py index 005701299..93a849ab3 100644 --- a/plinth/modules/users/views.py +++ b/plinth/modules/users/views.py @@ -15,13 +15,12 @@ from django.views.generic.edit import (CreateView, DeleteView, FormView, UpdateView) import plinth.modules.ssh.privileged as ssh_privileged -from plinth import actions, translation -from plinth.errors import ActionError +from plinth import translation from plinth.modules import first_boot from plinth.utils import is_user_admin from plinth.views import AppView -from . import get_last_admin_user +from . import get_last_admin_user, privileged from .forms import (CreateUserForm, FirstBootForm, UserChangePasswordForm, UserUpdateForm) @@ -59,6 +58,7 @@ class UserCreate(ContextMixin, SuccessMessageMixin, CreateView): class UserList(AppView, ContextMixin, django.views.generic.ListView): """View to list users.""" + model = User template_name = 'users_list.html' title = gettext_lazy('Users') @@ -72,6 +72,7 @@ class UserList(AppView, ContextMixin, django.views.generic.ListView): class UserUpdate(ContextMixin, SuccessMessageMixin, UpdateView): """View to update a user's details.""" + template_name = 'users_update.html' model = User form_class = UserUpdateForm @@ -101,7 +102,7 @@ class UserUpdate(ContextMixin, SuccessMessageMixin, UpdateView): ssh_keys = ssh_privileged.get_keys(self.object.username) initial['ssh_keys'] = ssh_keys.strip() initial['language'] = self.object.userprofile.language - except ActionError: + except Exception: pass return initial @@ -129,6 +130,7 @@ class UserDelete(ContextMixin, DeleteView): On GET, display a confirmation page. On POST, delete the user. """ + template_name = 'users_delete.html' model = User slug_field = 'username' @@ -136,6 +138,7 @@ class UserDelete(ContextMixin, DeleteView): title = gettext_lazy('Delete User') def __init__(self, *args, **kwargs): + """Initialize view, override delete method.""" super().__init__(*args, **kwargs) # Avoid a warning with Django 4.0 that delete member should not be @@ -149,9 +152,8 @@ class UserDelete(ContextMixin, DeleteView): messages.success(self.request, message) try: - actions.superuser_run('users', - ['remove-user', self.kwargs['slug']]) - except ActionError: + privileged.remove_user(self.kwargs['slug']) + except Exception: messages.error(self.request, _('Deleting LDAP user failed.')) def _delete(self, *args, **kwargs): @@ -177,6 +179,7 @@ class UserDelete(ContextMixin, DeleteView): class UserChangePassword(ContextMixin, SuccessMessageMixin, FormView): """View to change user password.""" + template_name = 'users_change_password.html' form_class = UserChangePasswordForm title = gettext_lazy('Change Password') @@ -216,8 +219,8 @@ class UserChangePassword(ContextMixin, SuccessMessageMixin, FormView): class FirstBootView(django.views.generic.CreateView): """Create user account and log the user in.""" - template_name = 'users_firstboot.html' + template_name = 'users_firstboot.html' form_class = FirstBootForm def dispatch(self, request, *args, **kwargs): @@ -231,15 +234,11 @@ class FirstBootView(django.views.generic.CreateView): def get_context_data(self, *args, **kwargs): """Add admin users to context data.""" context = super().get_context_data(*args, **kwargs) - - output = actions.superuser_run('users', ['get-group-users', 'admin']) - admin_users = output.strip().split('\n') if output.strip() else [] - context['admin_users'] = admin_users - + context['admin_users'] = privileged.get_group_users('admin') return context def get_form_kwargs(self): - """Make request available to the form (to insert messages)""" + """Make request available to the form (to insert messages).""" kwargs = super().get_form_kwargs() kwargs['request'] = self.request return kwargs diff --git a/plinth/tests/test_frontpage.py b/plinth/tests/test_frontpage.py index f09d84569..df6005ce1 100644 --- a/plinth/tests/test_frontpage.py +++ b/plinth/tests/test_frontpage.py @@ -109,33 +109,33 @@ def test_shortcut_list_web_apps_only(common_shortcuts): assert return_list == [cuts[0], cuts[1], cuts[2]] -@patch('plinth.actions.superuser_run') -def test_shortcut_list_with_username(superuser_run, common_shortcuts): +@patch('plinth.modules.users.privileged.get_user_groups') +def test_shortcut_list_with_username(get_user_groups, common_shortcuts): """Test listing for particular users.""" cuts = common_shortcuts return_list = Shortcut.list() assert return_list == [cuts[0], cuts[1], cuts[2], cuts[3]] - superuser_run.return_value = 'admin' + get_user_groups.return_value = ['admin'] return_list = Shortcut.list(username='admin') assert return_list == [cuts[0], cuts[1], cuts[2], cuts[3]] - superuser_run.return_value = 'group1' + get_user_groups.return_value = ['group1'] return_list = Shortcut.list(username='user1') assert return_list == [cuts[0], cuts[1], cuts[3]] - superuser_run.return_value = 'group1\ngroup2' + get_user_groups.return_value = ['group1', 'group2'] return_list = Shortcut.list(username='user2') assert return_list == [cuts[0], cuts[1], cuts[2], cuts[3]] cut = Shortcut('group2-web-app-component-1', 'name5', 'short2', url='url4', login_required=False, allowed_groups=['group3']) - superuser_run.return_value = 'group3' + get_user_groups.return_value = ['group3'] return_list = Shortcut.list(username='user3') assert return_list == [cuts[0], cuts[3], cut] - superuser_run.return_value = 'group4' + get_user_groups.return_value = ['group4'] return_list = Shortcut.list(username='user4') assert return_list == [cuts[0], cuts[3], cut] From 222563a4823f58a0d442a55c598f08dae7fd9007 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 08:25:57 -0700 Subject: [PATCH 69/90] *: Use privileged decorator for service actions Tests: - DONE: Unit tests work - DONE: Transmission - DONE: Enabling/disabling an app with a daemon works: transmission - DONE: Showing the status of whether the app is enabled with daemon is-enabled works. - DONE: A message is shown if app is enabled and service is not running - DONE: Service is stopped and re-started during backup - DONE: Adding user to share group during initial setup restarts the service - Not tested: Enabling/disabling a service with alias works (no such apps) - DONE: Restarting/try-restarting a service works - DONE: Masking/unmasking works - DONE: rsyslog is masked after initial setup - DONE: systemd-journald is try-restarted during initial setup - DONE: Avahi, email, security initial setup works - DONE: Fail2ban is unmasked and enabled - DONE: Enabling/disabling fail2ban is security app works - DONE: Enabling/disabling password authentication in SSH works - ?? Let's encrypt - Services are try-restarted during certificate setup, obtain, renew - Not tested: upgrade pagekite from version 1 Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/service | 130 ----------------------- plinth/daemon.py | 16 +-- plinth/modules/avahi/__init__.py | 8 +- plinth/modules/backups/api.py | 7 +- plinth/modules/config/__init__.py | 7 +- plinth/modules/email/__init__.py | 9 +- plinth/modules/letsencrypt/components.py | 9 +- plinth/modules/pagekite/__init__.py | 4 +- plinth/modules/security/__init__.py | 8 +- plinth/modules/security/views.py | 7 +- plinth/modules/ssh/views.py | 4 +- plinth/modules/users/__init__.py | 4 +- plinth/modules/wordpress/__init__.py | 3 +- plinth/privileged/__init__.py | 10 ++ plinth/privileged/service.py | 118 ++++++++++++++++++++ plinth/tests/test_daemon.py | 66 ++++++++++-- 16 files changed, 229 insertions(+), 181 deletions(-) delete mode 100755 actions/service create mode 100644 plinth/privileged/__init__.py create mode 100644 plinth/privileged/service.py diff --git a/actions/service b/actions/service deleted file mode 100755 index 2da7c4d3b..000000000 --- a/actions/service +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/python3 -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Wrapper to list and handle system services -""" - -import argparse -import os - -from plinth import action_utils -from plinth import app as app_module -from plinth import cfg, module_loader -from plinth.daemon import Daemon, RelatedDaemon - -cfg.read() -module_config_path = os.path.join(cfg.config_dir, 'modules-enabled') - - -def add_service_action(subparsers, action, help): - parser = subparsers.add_parser(action, help=help) - parser.add_argument('service', help='name of the service') - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - add_service_action(subparsers, 'start', 'start a service') - add_service_action(subparsers, 'stop', 'stop a service') - add_service_action(subparsers, 'enable', 'enable a service') - add_service_action(subparsers, 'disable', 'disable a service') - add_service_action(subparsers, 'restart', 'restart a service') - add_service_action(subparsers, 'try-restart', - 'restart a service if running') - add_service_action(subparsers, 'reload', 'reload a service') - add_service_action(subparsers, 'is-running', 'status of a service') - add_service_action(subparsers, 'is-enabled', 'status a service') - add_service_action(subparsers, 'mask', 'unmask a service') - add_service_action(subparsers, 'unmask', 'unmask a service') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_start(arguments): - action_utils.service_start(arguments.service) - - -def subcommand_stop(arguments): - action_utils.service_stop(arguments.service) - - -def subcommand_enable(arguments): - action_utils.service_enable(arguments.service) - - -def subcommand_disable(arguments): - action_utils.service_disable(arguments.service) - - -def subcommand_restart(arguments): - action_utils.service_restart(arguments.service) - - -def subcommand_try_restart(arguments): - action_utils.service_try_restart(arguments.service) - - -def subcommand_reload(arguments): - action_utils.service_reload(arguments.service) - - -def subcommand_mask(arguments): - action_utils.service_mask(arguments.service) - - -def subcommand_unmask(arguments): - action_utils.service_unmask(arguments.service) - - -def subcommand_is_enabled(arguments): - print(action_utils.service_is_enabled(arguments.service)) - - -def subcommand_is_running(arguments): - print(action_utils.service_is_running(arguments.service)) - - -def _get_managed_services(): - """Get a set of all services managed by FreedomBox.""" - services = set() - module_loader.load_modules() - app_module.apps_init() - for app in app_module.App.list(): - components = app.get_components_of_type(Daemon) - for component in components: - services.add(component.unit) - if component.alias: - services.add(component.alias) - - components = app.get_components_of_type(RelatedDaemon) - for component in components: - services.add(component.unit) - - return services - - -def _assert_service_is_managed_by_plinth(service_name): - managed_services = _get_managed_services() - if service_name not in managed_services: - msg = ("The service '%s' is not managed by FreedomBox. Access is only " - "permitted for services listed in the 'managed_services' " - "variable of any FreedomBox app.") % service_name - raise ValueError(msg) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - if hasattr(arguments, 'service'): - _assert_service_is_managed_by_plinth(arguments.service) - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/daemon.py b/plinth/daemon.py index 5d1935e83..de1d8d0a3 100644 --- a/plinth/daemon.py +++ b/plinth/daemon.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Component for managing a background daemon or any systemd unit. -""" +"""Component for managing a background daemon or any systemd unit.""" import socket import subprocess @@ -11,7 +9,7 @@ from django.utils.text import format_lazy from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy -from plinth import action_utils, actions, app +from plinth import action_utils, app class Daemon(app.LeaderComponent): @@ -70,15 +68,17 @@ class Daemon(app.LeaderComponent): def enable(self): """Run operations to enable the daemon/unit.""" - actions.superuser_run('service', ['enable', self.unit]) + from plinth.privileged import service as service_privileged + service_privileged.enable(self.unit) if self.alias: - actions.superuser_run('service', ['enable', self.alias]) + service_privileged.enable(self.alias) def disable(self): """Run operations to disable the daemon/unit.""" - actions.superuser_run('service', ['disable', self.unit]) + from plinth.privileged import service as service_privileged + service_privileged.disable(self.unit) if self.alias: - actions.superuser_run('service', ['disable', self.alias]) + service_privileged.disable(self.alias) def is_running(self): """Return whether the daemon/unit is running.""" diff --git a/plinth/modules/avahi/__init__.py b/plinth/modules/avahi/__init__.py index f06bbf271..420b4153b 100644 --- a/plinth/modules/avahi/__init__.py +++ b/plinth/modules/avahi/__init__.py @@ -1,11 +1,8 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app for service discovery. -""" +"""FreedomBox app for service discovery.""" from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import Daemon @@ -14,6 +11,7 @@ from plinth.modules.config import get_hostname from plinth.modules.firewall.components import Firewall from plinth.modules.names.components import DomainType from plinth.package import Packages +from plinth.privileged import service as service_privileged from plinth.signals import domain_added, domain_removed, post_hostname_change from plinth.utils import format_lazy @@ -90,7 +88,7 @@ class AvahiApp(app_module.App): # Reload avahi-daemon now that first-run does not reboot. After # performing FreedomBox Service (Plinth) package installation, new # Avahi files will be available and require restart. - actions.superuser_run('service', ['reload', 'avahi-daemon']) + service_privileged.reload('avahi-daemon') self.enable() diff --git a/plinth/modules/backups/api.py b/plinth/modules/backups/api.py index d2be5ca41..6763b396e 100644 --- a/plinth/modules/backups/api.py +++ b/plinth/modules/backups/api.py @@ -12,10 +12,11 @@ TODO: import logging -from plinth import action_utils, actions +from plinth import action_utils from plinth import app as app_module from plinth import setup from plinth.modules.apache import privileged as apache_privileged +from plinth.privileged import service as service_privileged from .components import BackupRestore @@ -318,12 +319,12 @@ class SystemServiceHandler(ServiceHandler): """Stop the service.""" self.was_running = action_utils.service_is_running(self.service) if self.was_running: - actions.superuser_run('service', ['stop', self.service]) + service_privileged.stop(self.service) def restart(self): """Restart the service if it was earlier running.""" if self.was_running: - actions.superuser_run('service', ['start', self.service]) + service_privileged.start(self.service) class ApacheServiceHandler(ServiceHandler): diff --git a/plinth/modules/config/__init__.py b/plinth/modules/config/__init__.py index 93cedeb84..9910c6798 100644 --- a/plinth/modules/config/__init__.py +++ b/plinth/modules/config/__init__.py @@ -13,6 +13,7 @@ from plinth.modules.apache import (get_users_with_website, user_of_uws_url, uws_url_of_user) from plinth.modules.names.components import DomainType from plinth.package import Packages +from plinth.privileged import service as service_privileged from plinth.signals import domain_added from . import privileged @@ -82,14 +83,14 @@ class ConfigApp(app_module.App): # systemd-journald is socket activated, it may not be running and it # does not support reload. - actions.superuser_run('service', ['try-restart', 'systemd-journald']) + service_privileged.try_restart('systemd-journald') # rsyslog when enabled, is activated by syslog.socket (shipped by # systemd). See: # https://www.freedesktop.org/wiki/Software/systemd/syslog/ . - actions.superuser_run('service', ['disable', 'rsyslog']) + service_privileged.disable('rsyslog') # Ensure that rsyslog is not started by something else as it is # installed by default on Debian systems. - actions.superuser_run('service', ['mask', 'rsyslog']) + service_privileged.mask('rsyslog') def get_domainname(): diff --git a/plinth/modules/email/__init__.py b/plinth/modules/email/__init__.py index 76cb5fa3b..03e2564dd 100644 --- a/plinth/modules/email/__init__.py +++ b/plinth/modules/email/__init__.py @@ -7,7 +7,7 @@ from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ import plinth.app -from plinth import actions, cfg, frontpage, menu +from plinth import cfg, frontpage, menu from plinth.daemon import Daemon from plinth.modules.apache.components import Webserver from plinth.modules.backups.components import BackupRestore @@ -15,6 +15,7 @@ from plinth.modules.config import get_domainname from plinth.modules.firewall.components import Firewall from plinth.modules.letsencrypt.components import LetsEncrypt from plinth.package import Packages, uninstall +from plinth.privileged import service as service_privileged from plinth.signals import domain_added, domain_removed from plinth.utils import format_lazy @@ -189,9 +190,9 @@ class EmailApp(plinth.app.App): privileged.setup_spam() # Restart daemons - actions.superuser_run('service', ['try-restart', 'postfix']) - actions.superuser_run('service', ['try-restart', 'dovecot']) - actions.superuser_run('service', ['try-restart', 'rspamd']) + service_privileged.try_restart('postfix') + service_privileged.try_restart('dovecot') + service_privileged.try_restart('rspamd') # Expose to public internet if old_version == 0: diff --git a/plinth/modules/letsencrypt/components.py b/plinth/modules/letsencrypt/components.py index 5fa760598..f951277fa 100644 --- a/plinth/modules/letsencrypt/components.py +++ b/plinth/modules/letsencrypt/components.py @@ -5,8 +5,9 @@ import logging import pathlib import threading -from plinth import actions, app +from plinth import app from plinth.modules.names.components import DomainName +from plinth.privileged import service as service_privileged from . import privileged @@ -168,7 +169,7 @@ class LetsEncrypt(app.FollowerComponent): self._copy_self_signed_certificates([domain]) for daemon in self.daemons: - actions.superuser_run('service', ['try-restart', daemon]) + service_privileged.try_restart(daemon) def get_status(self): """Return the status of certificates for all interested domains. @@ -213,7 +214,7 @@ class LetsEncrypt(app.FollowerComponent): self._copy_letsencrypt_certificates(interested_domains, lineage) for daemon in self.daemons: - actions.superuser_run('service', ['try-restart', daemon]) + service_privileged.try_restart(daemon) def on_certificate_renewed(self, domains, lineage): """Handle event when a certificate is renewed. @@ -247,7 +248,7 @@ class LetsEncrypt(app.FollowerComponent): self._copy_self_signed_certificates(interested_domains) for daemon in self.daemons: - actions.superuser_run('service', ['try-restart', daemon]) + service_privileged.try_restart(daemon) def on_certificate_deleted(self, domains, lineage): """Handle event when a certificate is deleted. diff --git a/plinth/modules/pagekite/__init__.py b/plinth/modules/pagekite/__init__.py index e85189b70..c9df15ec2 100644 --- a/plinth/modules/pagekite/__init__.py +++ b/plinth/modules/pagekite/__init__.py @@ -9,6 +9,7 @@ from plinth.daemon import Daemon from plinth.modules.backups.components import BackupRestore from plinth.modules.names.components import DomainType from plinth.package import Packages +from plinth.privileged import service as service_privileged from plinth.utils import format_lazy from . import manifest, utils @@ -103,5 +104,4 @@ class PagekiteApp(app_module.App): self.enable() if old_version == 1: - actions.superuser_run('service', - ['try-restart', PagekiteApp.DAEMON]) + service_privileged.try_restart(PagekiteApp.DAEMON) diff --git a/plinth/modules/security/__init__.py b/plinth/modules/security/__init__.py index d43a0bf00..e319dd879 100644 --- a/plinth/modules/security/__init__.py +++ b/plinth/modules/security/__init__.py @@ -7,12 +7,12 @@ from collections import defaultdict from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import menu from plinth.daemon import Daemon, RelatedDaemon from plinth.modules.backups.components import BackupRestore from plinth.package import Packages +from plinth.privileged import service as service_privileged from . import manifest, privileged @@ -55,7 +55,7 @@ class SecurityApp(app_module.App): if not old_version: enable_fail2ban() - actions.superuser_run('service', ['reload', 'fail2ban']) + service_privileged.reload('fail2ban') # Migrate to new config file. enabled = privileged.get_restricted_access_enabled() @@ -66,8 +66,8 @@ class SecurityApp(app_module.App): def enable_fail2ban(): """Unmask, enable and run the fail2ban service.""" - actions.superuser_run('service', ['unmask', 'fail2ban']) - actions.superuser_run('service', ['enable', 'fail2ban']) + service_privileged.unmask('fail2ban') + service_privileged.enable('fail2ban') def set_restricted_access(enabled): diff --git a/plinth/modules/security/views.py b/plinth/modules/security/views.py index 8d35c60f1..6a24fc87d 100644 --- a/plinth/modules/security/views.py +++ b/plinth/modules/security/views.py @@ -5,9 +5,10 @@ from django.contrib import messages from django.template.response import TemplateResponse from django.utils.translation import gettext as _ -from plinth import action_utils, actions +from plinth import action_utils from plinth.modules import security from plinth.modules.upgrades import is_backports_requested +from plinth.privileged import service as service_privileged from plinth.views import AppView from . import privileged @@ -63,9 +64,9 @@ def _apply_changes(request, old_status, new_status): if old_status['fail2ban_enabled'] != new_status['fail2ban_enabled']: if new_status['fail2ban_enabled']: - actions.superuser_run('service', ['enable', 'fail2ban']) + service_privileged.enable('fail2ban') else: - actions.superuser_run('service', ['disable', 'fail2ban']) + service_privileged.disable('fail2ban') def report(request): diff --git a/plinth/modules/ssh/views.py b/plinth/modules/ssh/views.py index d35c0b0ec..b1f84a231 100644 --- a/plinth/modules/ssh/views.py +++ b/plinth/modules/ssh/views.py @@ -4,8 +4,8 @@ from django.contrib import messages from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth.modules import ssh +from plinth.privileged import service as service_privileged from plinth.views import AppView from . import privileged @@ -48,7 +48,7 @@ class SshAppView(AppView): if passwd_auth_changed: privileged.set_password_authentication( not new_config['password_auth_disabled']) - actions.superuser_run('service', ['reload', 'ssh']) + service_privileged.reload('ssh') messages.success(self.request, _('Configuration updated')) return super().form_valid(form) diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py index 7176ac9a8..5e7f68e89 100644 --- a/plinth/modules/users/__init__.py +++ b/plinth/modules/users/__init__.py @@ -7,11 +7,11 @@ import subprocess from django.utils.text import format_lazy from django.utils.translation import gettext_lazy as _ -from plinth import actions from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import Daemon from plinth.package import Packages +from plinth.privileged import service as service_privileged from . import privileged from .components import UsersAndGroups @@ -131,4 +131,4 @@ def add_user_to_share_group(username, service=None): if username not in group_members: privileged.add_user_to_group(username, 'freedombox-share') if service: - actions.superuser_run('service', ['try-restart', service]) + service_privileged.try_restart(service) diff --git a/plinth/modules/wordpress/__init__.py b/plinth/modules/wordpress/__init__.py index c07872e89..7b933a79c 100644 --- a/plinth/modules/wordpress/__init__.py +++ b/plinth/modules/wordpress/__init__.py @@ -10,6 +10,7 @@ from plinth.modules.apache.components import Webserver from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.package import Packages +from plinth.privileged import service as service_privileged from plinth.utils import format_lazy from . import manifest, privileged @@ -106,7 +107,7 @@ class WordPressApp(app_module.App): self.enable() elif old_version < 3: # Apply changes to Apache configuration from v2 to v3. - actions.superuser_run('service', ['reload', 'apache2']) + service_privileged.reload('apache2') class WordPressBackupRestore(BackupRestore): diff --git a/plinth/privileged/__init__.py b/plinth/privileged/__init__.py new file mode 100644 index 000000000..82d80ca2b --- /dev/null +++ b/plinth/privileged/__init__.py @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Package holding all the privileged actions outside of apps.""" + +from .service import (disable, enable, is_enabled, is_running, mask, reload, + restart, start, stop, try_restart, unmask) + +__all__ = [ + 'disable', 'enable', 'is_enabled', 'is_running', 'mask', 'reload', + 'restart', 'start', 'stop', 'try_restart', 'unmask' +] diff --git a/plinth/privileged/service.py b/plinth/privileged/service.py new file mode 100644 index 000000000..81f04238b --- /dev/null +++ b/plinth/privileged/service.py @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""List and handle system services.""" + +import os + +from plinth import action_utils +from plinth import app as app_module +from plinth import cfg, module_loader +from plinth.actions import privileged +from plinth.daemon import Daemon, RelatedDaemon + +cfg.read() +module_config_path = os.path.join(cfg.config_dir, 'modules-enabled') + + +@privileged +def start(service: str): + """Start a service.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_start(service) + + +@privileged +def stop(service: str): + """Stop a running service.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_stop(service) + + +@privileged +def enable(service: str): + """Enable a service so that it start on system boot.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_enable(service) + + +@privileged +def disable(service: str): + """Disable a service so that it does not start on system boot.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_disable(service) + + +@privileged +def restart(service: str): + """Restart a service.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_restart(service) + + +@privileged +def try_restart(service: str): + """Restart a service if it is running.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_try_restart(service) + + +@privileged +def reload(service: str): + """Reload a service.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_reload(service) + + +@privileged +def mask(service: str): + """Mask a service.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_mask(service) + + +@privileged +def unmask(service: str): + """Unmask a service.""" + _assert_service_is_managed_by_plinth(service) + action_utils.service_unmask(service) + + +@privileged +def is_enabled(service: str) -> bool: + """Return whether a service is enabled.""" + _assert_service_is_managed_by_plinth(service) + return action_utils.service_is_enabled(service) + + +@privileged +def is_running(service: str) -> bool: + """Return whether a service is running.""" + _assert_service_is_managed_by_plinth(service) + return action_utils.service_is_running(service) + + +def _get_managed_services(): + """Get a set of all services managed by FreedomBox.""" + services = set() + module_loader.load_modules() + app_module.apps_init() + for app in app_module.App.list(): + components = app.get_components_of_type(Daemon) + for component in components: + services.add(component.unit) + if component.alias: + services.add(component.alias) + + components = app.get_components_of_type(RelatedDaemon) + for component in components: + services.add(component.unit) + + return services + + +def _assert_service_is_managed_by_plinth(service_name): + managed_services = _get_managed_services() + if service_name not in managed_services: + msg = ("The service '%s' is not managed by FreedomBox. Access is only " + "permitted for services listed in the 'managed_services' " + "variable of any FreedomBox app.") % service_name + raise ValueError(msg) diff --git a/plinth/tests/test_daemon.py b/plinth/tests/test_daemon.py index c28d73db2..8b68f5796 100644 --- a/plinth/tests/test_daemon.py +++ b/plinth/tests/test_daemon.py @@ -4,14 +4,23 @@ Test module for component managing system daemons and other systemd units. """ import socket +import subprocess from unittest.mock import Mock, call, patch import pytest -from plinth.app import App, FollowerComponent +from plinth.app import App, FollowerComponent, Info from plinth.daemon import (Daemon, RelatedDaemon, app_is_running, diagnose_netcat, diagnose_port_listening) +privileged_modules_to_mock = ['plinth.privileged.service'] + + +class AppTest(App): + """Test application that contains a daemon.""" + + app_id = 'test-app' + @pytest.fixture(name='daemon') def fixture_daemon(): @@ -19,6 +28,17 @@ def fixture_daemon(): return Daemon('test-daemon', 'test-unit') +@pytest.fixture(name='app_list') +def fixture_app_list(daemon): + """A list of apps on which tests are to be run.""" + app1 = AppTest() + app1.add(Info('test-app', 1)) + app1.add(daemon) + with patch('plinth.app.App.list') as app_list: + app_list.return_value = [app1] + yield app_list + + def test_initialization(): """Test that component is initialized properly.""" with pytest.raises(ValueError): @@ -56,25 +76,51 @@ def test_is_enabled(service_is_enabled, daemon): service_is_enabled.assert_has_calls([call('test-unit', strict_check=True)]) -@patch('plinth.actions.superuser_run') -def test_enable(superuser_run, daemon): +@patch('subprocess.run') +@patch('subprocess.call') +def test_enable(subprocess_call, subprocess_run, app_list, mock_privileged, + daemon): """Test that enabling the daemon works.""" daemon.enable() - superuser_run.assert_has_calls([call('service', ['enable', 'test-unit'])]) + subprocess_call.assert_has_calls( + [call(['systemctl', 'enable', 'test-unit'])]) + subprocess_run.assert_any_call(['systemctl', 'start', 'test-unit'], + stdout=subprocess.DEVNULL, check=False) + subprocess_call.reset_mock() daemon.alias = 'test-unit-2' daemon.enable() - superuser_run.assert_has_calls([ - call('service', ['enable', 'test-unit']), - call('service', ['enable', 'test-unit-2']) + subprocess_call.assert_has_calls([ + call(['systemctl', 'enable', 'test-unit']), + call(['systemctl', 'enable', 'test-unit-2']) ]) + subprocess_run.assert_any_call(['systemctl', 'start', 'test-unit'], + stdout=subprocess.DEVNULL, check=False) + subprocess_run.assert_any_call(['systemctl', 'start', 'test-unit-2'], + stdout=subprocess.DEVNULL, check=False) -@patch('plinth.actions.superuser_run') -def test_disable(superuser_run, daemon): +@patch('subprocess.run') +@patch('subprocess.call') +def test_disable(subprocess_call, subprocess_run, mock_privileged, daemon): """Test that disabling the daemon works.""" daemon.disable() - superuser_run.assert_has_calls([call('service', ['disable', 'test-unit'])]) + subprocess_call.assert_has_calls( + [call(['systemctl', 'disable', 'test-unit'])]) + subprocess_run.assert_any_call(['systemctl', 'stop', 'test-unit'], + stdout=subprocess.DEVNULL, check=False) + + subprocess_call.reset_mock() + daemon.alias = 'test-unit-2' + daemon.disable() + subprocess_call.assert_has_calls([ + call(['systemctl', 'disable', 'test-unit']), + call(['systemctl', 'disable', 'test-unit-2']) + ]) + subprocess_run.assert_any_call(['systemctl', 'stop', 'test-unit'], + stdout=subprocess.DEVNULL, check=False) + subprocess_run.assert_any_call(['systemctl', 'stop', 'test-unit-2'], + stdout=subprocess.DEVNULL, check=False) @patch('plinth.action_utils.service_is_running') From 9a4905e832f290bbbfe1bba1e8ba3c209124e7b8 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 10:01:54 -0700 Subject: [PATCH 70/90] backups: Use privileged decorator for backup actions Tests: - DONE: Functional tests works - DONE: Initial setup works - DONE: Borg repository is created at /var/lib/freedombox/borgbackup - DONE: With regular and with encrypted repository - DONE: Creating a repository works - DONE: Getting information works. When adding a existing location, incorrect password leads to error in the add form. - DONE: Listing archives works - DONE: Creating/restoring an archive works - DONE: Backup manifest is created in /var/lib/plinth/backups-manifests/ - DONE: Including an app that dumps/restores its settings works - DONE: Exporting an archive as tar works - DONE: Exporting a large archive yields reasonable download speeds. 31 MB/s. 1GB file in about 30 seconds. - DONE: Restoring from an uploaded archive works - DONE: Listing the apps inside an archive works before restore - DONE: Errors during operations are re-raises as simpler errors - DONE: Get info - DONE: List archives - DONE: Delete archive (not handled) - FAIL: Export tar - DONE: Init repo - DONE: Get archive apps (not handled) Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/backups | 349 ------------------ plinth/modules/backups/__init__.py | 58 +-- plinth/modules/backups/components.py | 18 +- plinth/modules/backups/privileged.py | 289 ++++++++++++++- plinth/modules/backups/repository.py | 68 ++-- plinth/modules/backups/tests/test_api.py | 27 +- plinth/modules/backups/tests/test_backups.py | 36 +- .../modules/backups/tests/test_components.py | 24 +- plinth/modules/backups/views.py | 4 +- 9 files changed, 362 insertions(+), 511 deletions(-) delete mode 100755 actions/backups diff --git a/actions/backups b/actions/backups deleted file mode 100755 index e83fa8b85..000000000 --- a/actions/backups +++ /dev/null @@ -1,349 +0,0 @@ -#!/usr/bin/python3 -# -*- mode: python -*- -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Wrapper to handle backups using borg-backups. -""" - -import argparse -import json -import os -import pathlib -import re -import subprocess -import sys -import tarfile - -from plinth.modules.backups import MANIFESTS_FOLDER -from plinth.utils import Version - -TIMEOUT = 30 -BACKUPS_DATA_PATH = pathlib.Path('/var/lib/plinth/backups-data/') - - -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - setup = subparsers.add_parser( - 'setup', help='Create repository if it does not already exist') - - init = subparsers.add_parser('init', help='Initialize a repository') - init.add_argument('--encryption', help='Encryption of the repository', - required=True) - - info = subparsers.add_parser('info', help='Show repository information') - - list_repo = subparsers.add_parser('list-repo', - help='List repository contents') - - create_archive = subparsers.add_parser('create-archive', - help='Create archive') - create_archive.add_argument('--paths', help='Paths to include in archive', - nargs='+') - create_archive.add_argument('--comment', - help='Comment text to add to archive', - default='') - - delete_archive = subparsers.add_parser('delete-archive', - help='Delete archive') - - export_help = 'Export archive contents as tar on stdout' - export_tar = subparsers.add_parser('export-tar', help=export_help) - - get_archive_apps = subparsers.add_parser( - 'get-archive-apps', help='Get list of apps included in archive') - - restore_archive = subparsers.add_parser( - 'restore-archive', help='Restore files from an archive') - restore_archive.add_argument('--destination', help='Destination', - required=True) - - for cmd in [ - info, init, list_repo, create_archive, delete_archive, export_tar, - get_archive_apps, restore_archive, setup - ]: - cmd.add_argument('--path', help='Repository or Archive path', - required=False) - cmd.add_argument('--ssh-keyfile', help='Path of private ssh key', - default=None) - - get_exported_archive_apps = subparsers.add_parser( - 'get-exported-archive-apps', - help='Get list of apps included in exported archive file') - get_exported_archive_apps.add_argument('--path', help='Tarball file path', - required=True) - - restore_exported_archive = subparsers.add_parser( - 'restore-exported-archive', - help='Restore files from an exported archive') - restore_exported_archive.add_argument('--path', help='Tarball file path', - required=True) - - dump_settings = subparsers.add_parser('dump-settings', - help='Dump JSON settings to a file') - dump_settings.add_argument('--app-id', - help='ID of the app to dump settings for') - - load_settings = subparsers.add_parser( - 'load-settings', help='Load JSON settings from a file') - load_settings.add_argument('--app-id', - help='ID of the app to load settings for') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_setup(arguments): - """Create repository if it does not already exist.""" - try: - run(['borg', 'info', arguments.path], arguments, check=True) - except subprocess.CalledProcessError: - path = os.path.dirname(arguments.path) - if not os.path.exists(path): - os.makedirs(path) - - init_repository(arguments, encryption='none') - - -def init_repository(arguments, encryption): - """Initialize a local or remote borg repository""" - if encryption != 'none': - if not _read_encryption_passphrase(arguments): - raise ValueError('No encryption passphrase provided') - - cmd = ['borg', 'init', '--encryption', encryption, arguments.path] - run(cmd, arguments) - - -def subcommand_init(arguments): - """Initialize the borg repository.""" - init_repository(arguments, encryption=arguments.encryption) - - -def subcommand_info(arguments): - """Show repository information.""" - run(['borg', 'info', '--json', arguments.path], arguments) - - -def subcommand_list_repo(arguments): - """List repository contents.""" - run(['borg', 'list', '--json', '--format="{comment}"', arguments.path], - arguments) - - -def _get_borg_version(arugments): - """Return the version of borgbackup.""" - process = run(['borg', '--version'], arugments, stdout=subprocess.PIPE) - return process.stdout.decode().split()[1] # Example: "borg 1.1.9" - - -def subcommand_create_archive(arguments): - """Create archive.""" - paths = filter(os.path.exists, arguments.paths) - command = ['borg', 'create', '--json'] - if arguments.comment: - comment = arguments.comment - if Version(_get_borg_version(arguments)) < Version('1.1.10'): - # Undo any placeholder escape sequences in comments as this version - # of borg does not support placeholders. XXX: Drop this code when - # support for borg < 1.1.10 is dropped. - comment = comment.replace('{{', '{').replace('}}', '}') - - command += ['--comment', comment] - - command += [arguments.path] + list(paths) - run(command, arguments) - - -def subcommand_delete_archive(arguments): - """Delete archive.""" - run(['borg', 'delete', arguments.path], arguments) - - -def _extract(archive_path, destination, arguments, locations=None): - """Extract archive contents.""" - prev_dir = os.getcwd() - borg_call = ['borg', 'extract', archive_path] - # do not extract any files when we get an empty locations list - if locations is not None: - borg_call.extend(locations) - - try: - os.chdir(os.path.expanduser(destination)) - # TODO: with python 3.7 use subprocess.run with the 'capture_output' - # argument - process = run(borg_call, arguments, check=False, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - if process.returncode != 0: - error = process.stderr.decode() - # Don't fail on the borg error when no files were matched - if "never matched" not in error: - raise subprocess.CalledProcessError(process.returncode, - process.args) - finally: - os.chdir(prev_dir) - - -def subcommand_export_tar(arguments): - """Export archive contents as tar stream on stdout.""" - run(['borg', 'export-tar', arguments.path, '-', '--tar-filter=gzip'], - arguments) - - -def _read_archive_file(archive, filepath, arguments): - """Read the content of a file inside an archive""" - borg_call = ['borg', 'extract', archive, filepath, '--stdout'] - return run(borg_call, arguments, stdout=subprocess.PIPE).stdout.decode() - - -def subcommand_get_archive_apps(arguments): - """Get list of apps included in archive.""" - manifest_folder = os.path.relpath(MANIFESTS_FOLDER, '/') - borg_call = [ - 'borg', 'list', arguments.path, manifest_folder, '--format', - '{path}{NEWLINE}' - ] - try: - borg_process = run(borg_call, arguments, stdout=subprocess.PIPE) - manifest_path = borg_process.stdout.decode().strip() - except subprocess.CalledProcessError: - sys.exit(1) - - manifest = None - if manifest_path: - manifest_data = _read_archive_file(arguments.path, manifest_path, - arguments) - manifest = json.loads(manifest_data) - - if manifest: - for app in _get_apps_of_manifest(manifest): - print(app['name']) - - -def _get_apps_of_manifest(manifest): - """Get apps of a manifest. - - Supports both dict format as well as list format of plinth <=0.42 - - """ - if isinstance(manifest, list): - apps = manifest - elif isinstance(manifest, dict) and 'apps' in manifest: - apps = manifest['apps'] - else: - raise RuntimeError('Unknown manifest format') - - return apps - - -def subcommand_get_exported_archive_apps(arguments): - """Get list of apps included in an exported archive file.""" - manifest = None - with tarfile.open(arguments.path) as tar_handle: - filenames = tar_handle.getnames() - for name in filenames: - if 'var/lib/plinth/backups-manifests/' in name \ - and name.endswith('.json'): - manifest_data = tar_handle.extractfile(name).read() - manifest = json.loads(manifest_data) - break - - if manifest: - for app in _get_apps_of_manifest(manifest): - print(app['name']) - - -def subcommand_restore_archive(arguments): - """Restore files from an archive.""" - _locations = json.loads(arguments.stdin) - locations = _locations['directories'] + _locations['files'] - locations = [os.path.relpath(location, '/') for location in locations] - _extract(arguments.path, arguments.destination, arguments, - locations=locations) - - -def subcommand_restore_exported_archive(arguments): - """Restore files from an exported archive.""" - locations = json.loads(arguments.stdin) - - with tarfile.open(arguments.path) as tar_handle: - for member in tar_handle.getmembers(): - path = '/' + member.name - if path in locations['files']: - tar_handle.extract(member, '/') - else: - for directory in locations['directories']: - if path.startswith(directory): - tar_handle.extract(member, '/') - break - - -def _assert_app_id(app_id): - """Check that app ID is correct.""" - if not re.fullmatch(r'[a-z0-9_]+', app_id): - raise Exception('Invalid App ID') - - -def subcommand_dump_settings(arguments): - """Dump an app's settings to a JSON file.""" - app_id = arguments.app_id - _assert_app_id(app_id) - BACKUPS_DATA_PATH.mkdir(exist_ok=True) - settings_path = BACKUPS_DATA_PATH / f'{app_id}-settings.json' - settings_path.write_text(arguments.stdin) - - -def subcommand_load_settings(arguments): - """Load an app's settings from a JSON file.""" - app_id = arguments.app_id - _assert_app_id(app_id) - settings_path = BACKUPS_DATA_PATH / f'{app_id}-settings.json' - try: - print(settings_path.read_text()) - except FileNotFoundError: - print('{}') - - -def _read_encryption_passphrase(arguments): - """Read encryption passphrase from stdin.""" - if arguments.stdin: - try: - return json.loads(arguments.stdin)['encryption_passphrase'] - except KeyError: - pass - - return None - - -def get_env(arguments): - """Create encryption and ssh kwargs out of given arguments""" - env = dict(os.environ, BORG_RELOCATED_REPO_ACCESS_IS_OK='yes', - LANG='C.UTF-8') - # Always provide BORG_PASSPHRASE (also if empty) so borg does not get stuck - # while asking for a passphrase. - encryption_passphrase = _read_encryption_passphrase(arguments) - env['BORG_PASSPHRASE'] = encryption_passphrase or '' - - return env - - -def run(cmd, arguments, check=True, **kwargs): - """Wrap the command with extra encryption passphrase handling.""" - env = get_env(arguments) - return subprocess.run(cmd, check=check, env=env, **kwargs) - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - arguments.stdin = sys.stdin.read() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py index 0583af152..f4ab92f1b 100644 --- a/plinth/modules/backups/__init__.py +++ b/plinth/modules/backups/__init__.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -FreedomBox app to manage backup archives. -""" +"""FreedomBox app to manage backup archives.""" import json import logging @@ -14,12 +12,11 @@ from django.utils.text import get_valid_filename from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_noop -from plinth import actions from plinth import app as app_module from plinth import cfg, glib, menu from plinth.package import Packages -from . import api +from . import api, privileged logger = logging.getLogger(__name__) @@ -27,7 +24,6 @@ _description = [ _('Backups allows creating and managing backup archives.'), ] -MANIFESTS_FOLDER = '/var/lib/plinth/backups-manifests/' # session variable name that stores when a backup file should be deleted SESSION_PATH_VARIABLE = 'fbx-backups-upload-path' @@ -69,8 +65,7 @@ class BackupsApp(app_module.App): """Install and configure the app.""" super().setup(old_version) from . import repository - actions.superuser_run( - 'backups', ['setup', '--path', repository.RootBorgRepository.PATH]) + privileged.setup(repository.RootBorgRepository.PATH) self.enable() # First time setup or upgrading from older versions. @@ -79,11 +74,11 @@ class BackupsApp(app_module.App): def _backup_handler(packet, encryption_passphrase=None): - """Performs backup operation on packet.""" - if not os.path.exists(MANIFESTS_FOLDER): - os.makedirs(MANIFESTS_FOLDER) + """Perform backup operation on packet.""" + if not os.path.exists(privileged.MANIFESTS_FOLDER): + os.makedirs(privileged.MANIFESTS_FOLDER) - manifest_path = os.path.join(MANIFESTS_FOLDER, + manifest_path = os.path.join(privileged.MANIFESTS_FOLDER, get_valid_filename(packet.path) + '.json') manifests = { 'apps': [{ @@ -97,17 +92,10 @@ def _backup_handler(packet, encryption_passphrase=None): paths = packet.directories + packet.files paths.append(manifest_path) - arguments = ['create-archive', '--path', packet.path] - if packet.archive_comment: - arguments += ['--comment', packet.archive_comment] - arguments += ['--paths'] + paths - input_data = '' - if encryption_passphrase: - input_data = json.dumps( - {'encryption_passphrase': encryption_passphrase}) - - actions.superuser_run('backups', arguments, input=input_data.encode()) + privileged.create_archive(packet.path, paths, + comment=packet.archive_comment, + encryption_passphrase=encryption_passphrase) def backup_by_schedule(data): @@ -123,34 +111,16 @@ def backup_by_schedule(data): exception=exception) -def get_exported_archive_apps(path): - """Get list of apps included in exported archive file.""" - arguments = ['get-exported-archive-apps', '--path', path] - output = actions.superuser_run('backups', arguments) - return output.splitlines() - - def _restore_exported_archive_handler(packet, encryption_passphrase=None): """Perform restore operation on packet.""" - locations = {'directories': packet.directories, 'files': packet.files} - locations_data = json.dumps(locations) - actions.superuser_run('backups', - ['restore-exported-archive', '--path', packet.path], - input=locations_data.encode()) + privileged.restore_exported_archive(packet.path, packet.directories, + packet.files) def restore_archive_handler(packet, encryption_passphrase=None): """Perform restore operation on packet.""" - locations = { - 'directories': packet.directories, - 'files': packet.files, - 'encryption_passphrase': encryption_passphrase - } - locations_data = json.dumps(locations) - arguments = [ - 'restore-archive', '--path', packet.path, '--destination', '/' - ] - actions.superuser_run('backups', arguments, input=locations_data.encode()) + privileged.restore_archive(packet.path, '/', packet.directories, + packet.files, encryption_passphrase) def restore_from_upload(path, app_ids=None): diff --git a/plinth/modules/backups/components.py b/plinth/modules/backups/components.py index 45165e856..6c668587b 100644 --- a/plinth/modules/backups/components.py +++ b/plinth/modules/backups/components.py @@ -1,12 +1,11 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -App component for other apps to use backup/restore functionality. -""" +"""App component for other apps to use backup/restore functionality.""" import copy -import json -from plinth import actions, app +from plinth import app + +from . import privileged def _validate_directories_and_files(section): @@ -150,19 +149,14 @@ class BackupRestore(app.FollowerComponent): except Exception: pass - input_ = json.dumps(data).encode() - actions.superuser_run('backups', - ['dump-settings', '--app-id', self.app_id], - input=input_) + privileged.dump_settings(self.app_id, data) def _settings_restore_post(self): """Read from a file and restore keys to kvstore.""" if not self.settings: return - output = actions.superuser_run( - 'backups', ['load-settings', '--app-id', self.app_id]) - data = json.loads(output) + data = privileged.load_settings(self.app_id) from plinth import kvstore for key, value in data.items(): diff --git a/plinth/modules/backups/privileged.py b/plinth/modules/backups/privileged.py index 5ba4c91b6..429eedc75 100644 --- a/plinth/modules/backups/privileged.py +++ b/plinth/modules/backups/privileged.py @@ -1,12 +1,20 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -"""Configure backups and sshfs.""" +"""Configure backups (with borg) and sshfs.""" +import json import os +import pathlib +import re import subprocess +import tarfile +from typing import Optional, Union from plinth.actions import privileged +from plinth.utils import Version TIMEOUT = 30 +BACKUPS_DATA_PATH = pathlib.Path('/var/lib/plinth/backups-data/') +MANIFESTS_FOLDER = '/var/lib/plinth/backups-manifests/' class AlreadyMountedError(Exception): @@ -14,8 +22,9 @@ class AlreadyMountedError(Exception): @privileged -def mount(mountpoint: str, remote_path: str, ssh_keyfile: str = None, - password: str = None, user_known_hosts_file: str = '/dev/null'): +def mount(mountpoint: str, remote_path: str, ssh_keyfile: Optional[str] = None, + password: Optional[str] = None, + user_known_hosts_file: str = '/dev/null'): """Mount a remote ssh path via sshfs.""" try: _validate_mountpoint(mountpoint) @@ -28,12 +37,12 @@ def mount(mountpoint: str, remote_path: str, ssh_keyfile: str = None, # 'reconnect', 'ServerAliveInternal' and 'ServerAliveCountMax' allow the # client (FreedomBox) to keep control of the SSH connection even when the # SSH server misbehaves. Without these options, other commands such as - # '/usr/share/plinth/actions/storage usage-info', 'df', - # '/usr/share/plinth/actions/sshfs is-mounted', or 'mountpoint' might block - # indefinitely (even when manually invoked from the command line). This - # situation has some lateral effects, causing major system instability in - # the course of ~11 days, and leaving the system in such state that the - # only solution is a reboot. + # '/usr/share/plinth/actions/actions storage usage_info --no-args', 'df', + # '/usr/share/plinth/actions/actions sshfs is_mounted --no-args', or + # 'mountpoint' might block indefinitely (even when manually invoked from + # the command line). This situation has some lateral effects, causing major + # system instability in the course of ~11 days, and leaving the system in + # such state that the only solution is a reboot. cmd = [ 'sshfs', remote_path, mountpoint, '-o', f'UserKnownHostsFile={user_known_hosts_file}', '-o', @@ -52,7 +61,7 @@ def mount(mountpoint: str, remote_path: str, ssh_keyfile: str = None, @privileged -def subcommand_umount(mountpoint: str): +def umount(mountpoint: str): """Unmount a mountpoint.""" subprocess.run(['umount', mountpoint], check=True) @@ -82,6 +91,260 @@ def _is_mounted(mountpoint): @privileged -def is_mounted(arguments) -> bool: - """Print whether a path is already mounted.""" - return _is_mounted(arguments.mountpoint) +def is_mounted(mount_point: str) -> bool: + """Return whether a path is already mounted.""" + return _is_mounted(mount_point) + + +@privileged +def setup(path: str): + """Create repository if it does not already exist.""" + try: + _run(['borg', 'info', path], check=True) + except subprocess.CalledProcessError: + parent = os.path.dirname(path) + if not os.path.exists(parent): + os.makedirs(parent) + + _init_repository(path, encryption='none') + + +def _init_repository(path: str, encryption: str, + encryption_passphrase: Optional[str] = None): + """Initialize a local or remote borg repository.""" + if encryption != 'none': + if not encryption_passphrase: + raise ValueError('No encryption passphrase provided') + + cmd = ['borg', 'init', '--encryption', encryption, path] + _run(cmd, encryption_passphrase) + + +@privileged +def init(path: str, encryption: str, + encryption_passphrase: Optional[str] = None): + """Initialize the borg repository.""" + _init_repository(path, encryption, encryption_passphrase) + + +@privileged +def info(path: str, encryption_passphrase: Optional[str] = None) -> dict: + """Show repository information.""" + process = _run(['borg', 'info', '--json', path], encryption_passphrase, + stdout=subprocess.PIPE) + return json.loads(process.stdout.decode()) + + +@privileged +def list_repo(path: str, encryption_passphrase: Optional[str] = None) -> dict: + """List repository contents.""" + process = _run(['borg', 'list', '--json', '--format="{comment}"', path], + encryption_passphrase, stdout=subprocess.PIPE) + return json.loads(process.stdout.decode()) + + +def _get_borg_version(): + """Return the version of borgbackup.""" + process = _run(['borg', '--version'], stdout=subprocess.PIPE) + return process.stdout.decode().split()[1] # Example: "borg 1.1.9" + + +@privileged +def create_archive(path: str, paths: list[str], comment: Optional[str] = None, + encryption_passphrase: Optional[str] = None): + """Create archive.""" + existing_paths = filter(os.path.exists, paths) + command = ['borg', 'create', '--json'] + if comment: + if Version(_get_borg_version()) < Version('1.1.10'): + # Undo any placeholder escape sequences in comments as this version + # of borg does not support placeholders. XXX: Drop this code when + # support for borg < 1.1.10 is dropped. + comment = comment.replace('{{', '{').replace('}}', '}') + + command += ['--comment', comment] + + command += [path] + list(existing_paths) + _run(command, encryption_passphrase) + + +@privileged +def delete_archive(path: str, encryption_passphrase: Optional[str] = None): + """Delete archive.""" + _run(['borg', 'delete', path], encryption_passphrase) + + +def _extract(archive_path, destination, encryption_passphrase, locations=None): + """Extract archive contents.""" + prev_dir = os.getcwd() + borg_call = ['borg', 'extract', archive_path] + # do not extract any files when we get an empty locations list + if locations is not None: + borg_call.extend(locations) + + try: + os.chdir(os.path.expanduser(destination)) + # TODO: with python 3.7 use subprocess.run with the 'capture_output' + # argument + process = _run(borg_call, encryption_passphrase, check=False, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if process.returncode != 0: + error = process.stderr.decode() + # Don't fail on the borg error when no files were matched + if "never matched" not in error: + raise subprocess.CalledProcessError(process.returncode, + process.args) + finally: + os.chdir(prev_dir) + + +@privileged +def export_tar(path: str, encryption_passphrase: Optional[str] = None): + """Export archive contents as tar stream on stdout.""" + _run(['borg', 'export-tar', path, '-', '--tar-filter=gzip'], + encryption_passphrase) + + +def _read_archive_file(archive, filepath, encryption_passphrase): + """Read the content of a file inside an archive.""" + borg_call = ['borg', 'extract', archive, filepath, '--stdout'] + return _run(borg_call, encryption_passphrase, + stdout=subprocess.PIPE).stdout.decode() + + +@privileged +def get_archive_apps(path: str, + encryption_passphrase: Optional[str] = None) -> list[str]: + """Get list of apps included in archive.""" + manifest_folder = os.path.relpath(MANIFESTS_FOLDER, '/') + borg_call = [ + 'borg', 'list', path, manifest_folder, '--format', '{path}{NEWLINE}' + ] + try: + borg_process = _run(borg_call, encryption_passphrase, + stdout=subprocess.PIPE) + manifest_path = borg_process.stdout.decode().strip() + except subprocess.CalledProcessError: + raise RuntimeError('Borg exited unsuccessfully') + + manifest = None + if manifest_path: + manifest_data = _read_archive_file(path, manifest_path, + encryption_passphrase) + manifest = json.loads(manifest_data) + + archive_apps = [] + if manifest: + for app in _get_apps_of_manifest(manifest): + archive_apps.append(app['name']) + + return archive_apps + + +def _get_apps_of_manifest(manifest): + """Get apps of a manifest. + + Supports both dict format as well as list format of plinth <=0.42 + + """ + if isinstance(manifest, list): + apps = manifest + elif isinstance(manifest, dict) and 'apps' in manifest: + apps = manifest['apps'] + else: + raise RuntimeError('Unknown manifest format') + + return apps + + +@privileged +def get_exported_archive_apps(path: str) -> list[str]: + """Get list of apps included in an exported archive file.""" + manifest = None + with tarfile.open(path) as tar_handle: + filenames = tar_handle.getnames() + for name in filenames: + if 'var/lib/plinth/backups-manifests/' in name \ + and name.endswith('.json'): + manifest_data = tar_handle.extractfile(name).read() + manifest = json.loads(manifest_data) + break + + app_names = [] + if manifest: + for app in _get_apps_of_manifest(manifest): + app_names.append(app['name']) + + return app_names + + +@privileged +def restore_archive(archive_path: str, destination: str, + directories: list[str], files: list[str], + encryption_passphrase: Optional[str] = None): + """Restore files from an archive.""" + locations_all = directories + files + locations_all = [ + os.path.relpath(location, '/') for location in locations_all + ] + _extract(archive_path, destination, encryption_passphrase, + locations=locations_all) + + +@privileged +def restore_exported_archive(path: str, directories: list[str], + files: list[str]): + """Restore files from an exported archive.""" + with tarfile.open(path) as tar_handle: + for member in tar_handle.getmembers(): + path = '/' + member.name + if path in files: + tar_handle.extract(member, '/') + else: + for directory in directories: + if path.startswith(directory): + tar_handle.extract(member, '/') + break + + +def _assert_app_id(app_id): + """Check that app ID is correct.""" + if not re.fullmatch(r'[a-z0-9_]+', app_id): + raise Exception('Invalid App ID') + + +@privileged +def dump_settings(app_id: str, settings: dict[str, Union[int, float, bool, + str]]): + """Dump an app's settings to a JSON file.""" + _assert_app_id(app_id) + BACKUPS_DATA_PATH.mkdir(exist_ok=True) + settings_path = BACKUPS_DATA_PATH / f'{app_id}-settings.json' + settings_path.write_text(json.dumps(settings)) + + +@privileged +def load_settings(app_id: str) -> dict[str, Union[int, float, bool, str]]: + """Load an app's settings from a JSON file.""" + _assert_app_id(app_id) + settings_path = BACKUPS_DATA_PATH / f'{app_id}-settings.json' + try: + return json.loads(settings_path.read_text()) + except FileNotFoundError: + return {} + + +def _get_env(encryption_passphrase: Optional[str] = None): + """Create encryption and ssh kwargs out of given arguments.""" + env = dict(os.environ, BORG_RELOCATED_REPO_ACCESS_IS_OK='yes', + LANG='C.UTF-8') + # Always provide BORG_PASSPHRASE (also if empty) so borg does not get stuck + # while asking for a passphrase. + env['BORG_PASSPHRASE'] = encryption_passphrase or '' + return env + + +def _run(cmd, encryption_passphrase=None, check=True, **kwargs): + """Wrap the command with extra encryption passphrase handling.""" + env = _get_env(encryption_passphrase) + return subprocess.run(cmd, check=check, env=env, **kwargs) diff --git a/plinth/modules/backups/repository.py b/plinth/modules/backups/repository.py index f63ae3186..9fc7101f3 100644 --- a/plinth/modules/backups/repository.py +++ b/plinth/modules/backups/repository.py @@ -4,7 +4,6 @@ import abc import contextlib import io -import json import logging import os import re @@ -13,8 +12,7 @@ from uuid import uuid1 import paramiko from django.utils.translation import gettext_lazy as _ -from plinth import actions, cfg -from plinth.errors import ActionError +from plinth import cfg from plinth.utils import format_lazy from . import (_backup_handler, api, errors, get_known_hosts_path, privileged, @@ -137,8 +135,10 @@ class BaseBorgRepository(abc.ABC): def get_info(self): """Return Borg information about a repository.""" - output = self.run(['info', '--path', self.borg_path]) - output = json.loads(output) + with self._handle_errors(): + output = privileged.info(self.borg_path, + self._get_encryption_passpharse()) + if output['encryption']['mode'] == 'none' and \ self._get_encryption_data(): raise errors.BorgUnencryptedRepository( @@ -147,7 +147,7 @@ class BaseBorgRepository(abc.ABC): return output def get_view_content(self): - """Get archives with additional information as needed by the view""" + """Get archives with additional information as needed by the view.""" repository = { 'uuid': self.uuid, 'name': self.name, @@ -160,7 +160,7 @@ class BaseBorgRepository(abc.ABC): repository['mounted'] = self.is_mounted if repository['mounted']: repository['archives'] = self.list_archives() - except (errors.BorgError, ActionError) as err: + except (errors.BorgError, Exception) as err: repository['error'] = str(err) return repository @@ -170,8 +170,9 @@ class BaseBorgRepository(abc.ABC): def list_archives(self): """Return list of archives in this repository.""" - output = self.run(['list-repo', '--path', self.borg_path]) - archives = json.loads(output)['archives'] + with self._handle_errors(): + archives = privileged.list_repo( + self.borg_path, self._get_encryption_passpharse())['archives'] return sorted(archives, key=lambda archive: archive['start'], reverse=True) @@ -186,7 +187,9 @@ class BaseBorgRepository(abc.ABC): def delete_archive(self, archive_name): """Delete an archive with given name from this repository.""" archive_path = self._get_archive_path(archive_name) - self.run(['delete-archive', '--path', archive_path]) + with self._handle_errors(): + privileged.delete_archive(archive_path, + self._get_encryption_passpharse()) def initialize(self): """Initialize / create a borg repository.""" @@ -196,8 +199,9 @@ class BaseBorgRepository(abc.ABC): encryption = 'repokey' try: - self.run( - ['init', '--path', self.borg_path, '--encryption', encryption]) + with self._handle_errors(): + privileged.init(self.borg_path, encryption, + self._get_encryption_passpharse()) except errors.BorgRepositoryExists: pass @@ -219,25 +223,13 @@ class BaseBorgRepository(abc.ABC): except Exception as exception: self.reraise_known_error(exception) - def _run(self, cmd, arguments, superuser=True, **kwargs): - """Run a backups or sshfs action script command.""" - try: - if superuser: - return actions.superuser_run(cmd, arguments, **kwargs) - - return actions.run(cmd, arguments, **kwargs) - except ActionError as err: - self.reraise_known_error(err) - - def run(self, arguments, superuser=True): - """Add credentials and run a backups action script command.""" + def _get_encryption_passpharse(self): + """Return encryption passphrase or raise an exception.""" for key in self.credentials.keys(): if key not in self.known_credentials: raise ValueError('Unknown credentials entry: %s' % key) - input_data = json.dumps(self._get_encryption_data()) - return self._run('backups', arguments, superuser=superuser, - input=input_data.encode()) + return self.credentials.get('encryption_passphrase', None) def get_download_stream(self, archive_name): """Return an stream of .tar.gz binary data for a backup archive.""" @@ -264,11 +256,16 @@ class BaseBorgRepository(abc.ABC): return chunk - args = ['export-tar', '--path', self._get_archive_path(archive_name)] - input_data = json.dumps(self._get_encryption_data()) - proc = self._run('backups', args, run_in_background=True) - proc.stdin.write(input_data.encode()) + with self._handle_errors(): + proc, read_fd, input_ = privileged.export_tar( + self._get_archive_path(archive_name), + self._get_encryption_passpharse(), _raw_output=True) + + os.close(read_fd) # Don't use the pipe for communication, just stdout + proc.stdin.write(input_) proc.stdin.close() + proc.stderr.close() # writing to stderr in child will cause SIGPIPE + return BufferedReader(proc.stdout) def _get_archive_path(self, archive_name): @@ -278,7 +275,7 @@ class BaseBorgRepository(abc.ABC): @staticmethod def reraise_known_error(err): """Look whether the caught error is known and reraise it accordingly""" - caught_error = str(err) + caught_error = str((err, err.args)) for known_error in KNOWN_ERRORS: for error in known_error['errors']: if re.search(error, caught_error): @@ -297,8 +294,9 @@ class BaseBorgRepository(abc.ABC): def get_archive_apps(self, archive_name): """Get list of apps included in an archive.""" archive_path = self._get_archive_path(archive_name) - output = self.run(['get-archive-apps', '--path', archive_path]) - return output.splitlines() + with self._handle_errors(): + return privileged.get_archive_apps( + archive_path, self._get_encryption_passpharse()) def restore_archive(self, archive_name, app_ids=None): """Restore an archive from this repository to the system.""" @@ -474,7 +472,7 @@ class SshBorgRepository(BaseBorgRepository): if os.path.exists(self._mountpoint): try: self.umount() - except ActionError: + except Exception: pass if not os.listdir(self._mountpoint): os.rmdir(self._mountpoint) diff --git a/plinth/modules/backups/tests/test_api.py b/plinth/modules/backups/tests/test_api.py index cdcd6fa7d..484de1c70 100644 --- a/plinth/modules/backups/tests/test_api.py +++ b/plinth/modules/backups/tests/test_api.py @@ -157,8 +157,10 @@ class TestBackupProcesses: @staticmethod @patch('plinth.action_utils.webserver_is_enabled') @patch('plinth.action_utils.service_is_running') - @patch('plinth.actions.superuser_run') - def test__shutdown_services(run, service_is_running, webserver_is_enabled): + @patch('plinth.privileged.service.stop') + @patch('plinth.modules.apache.privileged.disable') + def test__shutdown_services(apache_disable, service_stop, + service_is_running, webserver_is_enabled): """Test that services are stopped in correct order.""" components = [_get_backup_component('a'), _get_backup_component('b')] service_is_running.return_value = True @@ -182,17 +184,13 @@ class TestBackupProcesses: [call('b', kind='site'), call('a', kind='site')]) - calls = [ - call('apache', ['disable', '--name', 'b', '--kind', 'site']), - call('service', ['stop', 'b']), - call('apache', ['disable', '--name', 'a', '--kind', 'site']), - call('service', ['stop', 'a']) - ] - run.assert_has_calls(calls) + apache_disable.assert_has_calls([call('b', 'site'), call('a', 'site')]) + service_stop.assert_has_calls([call('b'), call('a')]) @staticmethod - @patch('plinth.actions.superuser_run') - def test__restore_services(run): + @patch('plinth.privileged.service.start') + @patch('plinth.modules.apache.privileged.enable') + def test__restore_services(apache_enable, service_start): """Test that services are restored in correct order.""" original_state = [ api.SystemServiceHandler(None, 'a-service'), @@ -211,11 +209,8 @@ class TestBackupProcesses: original_state[2].was_enabled = True original_state[3].was_enabled = False api._restore_services(original_state) - calls = [ - call('service', ['start', 'a-service']), - call('apache', ['enable', '--name', 'c-service', '--kind', 'site']) - ] - run.assert_has_calls(calls) + service_start.assert_has_calls([call('a-service')]) + apache_enable.assert_has_calls([call('c-service', 'site')]) @staticmethod def test__run_operation(): diff --git a/plinth/modules/backups/tests/test_backups.py b/plinth/modules/backups/tests/test_backups.py index d8007cef9..517a63dd1 100644 --- a/plinth/modules/backups/tests/test_backups.py +++ b/plinth/modules/backups/tests/test_backups.py @@ -3,7 +3,6 @@ Test the backups action script. """ -import json import os import pathlib import subprocess @@ -11,8 +10,8 @@ import uuid import pytest -from plinth import actions from plinth.modules import backups +from plinth.modules.backups import privileged from plinth.modules.backups.repository import BorgRepository, SshBorgRepository from plinth.tests import config as test_config @@ -94,11 +93,8 @@ def test_create_export_delete_archive(data_directory, backup_directory): repository = BorgRepository(str(path)) repository.initialize() archive_path = "::".join([str(path), archive_name]) - actions.superuser_run('backups', [ - 'create-archive', '--path', archive_path, '--comment', archive_comment, - '--paths', - str(data_directory) - ]) + privileged.create_archive(archive_path, [str(data_directory)], + archive_comment) archive = repository.list_archives()[0] assert archive['name'] == archive_name @@ -118,28 +114,18 @@ def test_remote_backup_actions(): """ credentials = _get_credentials(add_encryption_passphrase=True) path = os.path.join(test_config.backups_ssh_path, str(uuid.uuid1())) - arguments = ['init', '--path', path, '--encryption', 'repokey'] - arguments, kwargs = _append_borg_arguments(arguments, credentials) - actions.superuser_run('backups', arguments, **kwargs) + privileged.init(path, 'repokey', **_get_borg_arguments(credentials)) - arguments = ['info', '--path', path] - arguments, kwargs = _append_borg_arguments(arguments, credentials) - info = actions.superuser_run('backups', arguments, **kwargs) - info = json.loads(info) + info = privileged.info(path, **_get_borg_arguments(credentials)) assert info['encryption']['mode'] == 'repokey' -def _append_borg_arguments(arguments, credentials): - """Append run arguments for running borg directly""" - kwargs = {} - passphrase = credentials.get('encryption_passphrase', None) - if passphrase: - kwargs['input'] = json.dumps({'encryption_passphrase': passphrase}) - - if 'ssh_keyfile' in credentials and credentials['ssh_keyfile']: - arguments += ['--ssh-keyfile', credentials['ssh_keyfile']] - - return (arguments, kwargs) +def _get_borg_arguments(credentials): + """Get credential arguments for running borg privileged actions.""" + return { + 'passphrase': credentials.get('encryption_passphrase', None), + 'ssh_keyfile': credentials.get('ssh_keyfile') + } @pytest.mark.usefixtures('needs_ssh_config') diff --git a/plinth/modules/backups/tests/test_components.py b/plinth/modules/backups/tests/test_components.py index 29a88d91d..e5cc39b96 100644 --- a/plinth/modules/backups/tests/test_components.py +++ b/plinth/modules/backups/tests/test_components.py @@ -3,7 +3,6 @@ Test the App components provides by backups app. """ -import json from unittest.mock import call, patch import pytest @@ -235,8 +234,8 @@ def test_backup_restore_hooks(backup_restore): @pytest.mark.django_db -@patch('plinth.actions.superuser_run') -def test_backup_restore_backup_pre(run, backup_restore): +@patch('plinth.modules.backups.privileged.dump_settings') +def test_backup_restore_backup_pre(dump_settings, backup_restore): """Test running backup-pre hook.""" packet = None kvstore.set('setting-1', 'value-1') @@ -244,32 +243,27 @@ def test_backup_restore_backup_pre(run, backup_restore): component = BackupRestore('test-backup-restore') component.backup_pre(packet) - run.assert_has_calls([]) + dump_settings.assert_has_calls([]) backup_restore.backup_pre(packet) - input_ = {'setting-1': 'value-1'} - run.assert_has_calls([ - call('backups', ['dump-settings', '--app-id', 'testapp'], - input=json.dumps(input_).encode()) - ]) + dump_settings.assert_has_calls([call('testapp', {'setting-1': 'value-1'})]) @pytest.mark.django_db -@patch('plinth.actions.superuser_run') -def test_backup_restore_restore_post(run, backup_restore): +@patch('plinth.modules.backups.privileged.load_settings') +def test_backup_restore_restore_post(load_settings, backup_restore): """Test running restore-post hook.""" packet = None backup_restore.app_id = 'testapp' component = BackupRestore('test-backup-restore') component.restore_post(packet) - run.assert_has_calls([]) + load_settings.assert_has_calls([]) output = {'setting-1': 'value-1'} - run.return_value = json.dumps(output) + load_settings.return_value = output backup_restore.restore_post(packet) - run.assert_has_calls( - [call('backups', ['load-settings', '--app-id', 'testapp'])]) + load_settings.assert_has_calls([call('testapp')]) assert kvstore.get('setting-1') == 'value-1' with pytest.raises(Exception): diff --git a/plinth/modules/backups/views.py b/plinth/modules/backups/views.py index d613e7b18..fdadea719 100644 --- a/plinth/modules/backups/views.py +++ b/plinth/modules/backups/views.py @@ -25,7 +25,7 @@ from plinth.modules import backups, storage from plinth.views import AppView from . import (SESSION_PATH_VARIABLE, api, forms, get_known_hosts_path, - is_ssh_hostkey_verified) + is_ssh_hostkey_verified, privileged) from .decorators import delete_tmp_backup_file from .repository import (BorgRepository, SshBorgRepository, get_instance, get_repositories) @@ -238,7 +238,7 @@ class RestoreFromUploadView(BaseRestoreView): def _get_included_apps(self): """Save some data used to instantiate the form.""" path = self.request.session.get(SESSION_PATH_VARIABLE) - return backups.get_exported_archive_apps(path) + return privileged.get_exported_archive_apps(path) def form_valid(self, form): """Restore files from the archive on valid form submission.""" From 0bda4843a7b8a3e227b5e4bdf4078a2d9561c5de Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 3 Sep 2022 16:15:57 -0700 Subject: [PATCH 71/90] *: Use privileged decorator for package actions Tests: - DONE: Check if package manager is busy works - DONE: Power app shows status in app/restart/shutdown pages - DONE: Upgrades app shows in app page and first boot wizard page - DONE: When attempting force upgrade, busy state results in a back-off - DONE: An app's packages can be installed/uninstalled successfully - DONE: apt update is run before install - DONE: If network is not available during package install, error message is shown - DONE: Filtering packages with configuration file prompts works. Tested with firewall 1.0.3 to 1.2.1. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/power/views.py | 9 +- plinth/modules/upgrades/views.py | 7 +- plinth/package.py | 91 +++-------- plinth/privileged/__init__.py | 7 +- .../packages => plinth/privileged/packages.py | 149 ++++++------------ plinth/setup.py | 3 +- 6 files changed, 91 insertions(+), 175 deletions(-) rename actions/packages => plinth/privileged/packages.py (74%) mode change 100755 => 100644 diff --git a/plinth/modules/power/views.py b/plinth/modules/power/views.py index 2a53b8a95..c4198f09e 100644 --- a/plinth/modules/power/views.py +++ b/plinth/modules/power/views.py @@ -22,7 +22,8 @@ class PowerAppView(AppView): def get_context_data(self, *args, **kwargs): """Add additional context data for template.""" context = super().get_context_data(*args, **kwargs) - context['pkg_manager_is_busy'] = package.is_package_manager_busy() + is_busy = package.is_package_manager_busy() + context['pkg_manager_is_busy'] = is_busy return context @@ -36,12 +37,13 @@ def restart(request): app = app_module.App.get('power') form = Form(prefix='power') + is_busy = package.is_package_manager_busy() return TemplateResponse( request, 'power_restart.html', { 'title': app.info.name, 'form': form, 'manual_page': app.info.manual_page, - 'pkg_manager_is_busy': package.is_package_manager_busy() + 'pkg_manager_is_busy': is_busy }) @@ -55,10 +57,11 @@ def shutdown(request): app = app_module.App.get('power') form = Form(prefix='power') + is_busy = package.is_package_manager_busy() return TemplateResponse( request, 'power_shutdown.html', { 'title': app.info.name, 'form': form, 'manual_page': app.info.manual_page, - 'pkg_manager_is_busy': package.is_package_manager_busy() + 'pkg_manager_is_busy': is_busy }) diff --git a/plinth/modules/upgrades/views.py b/plinth/modules/upgrades/views.py index 98700f3de..0736ff000 100644 --- a/plinth/modules/upgrades/views.py +++ b/plinth/modules/upgrades/views.py @@ -12,8 +12,9 @@ from django.utils.translation import gettext as _ from django.views.generic import TemplateView from django.views.generic.edit import FormView -from plinth import __version__, package +from plinth import __version__ from plinth.modules import first_boot, upgrades +from plinth.privileged import packages as packages_privileged from plinth.views import AppView from . import privileged @@ -41,7 +42,7 @@ class UpgradesConfigurationView(AppView): context['can_activate_backports'] = upgrades.can_activate_backports() context['is_backports_requested'] = upgrades.is_backports_requested() context['is_busy'] = (_is_updating() - or package.is_package_manager_busy()) + or packages_privileged.is_package_manager_busy()) context['log'] = privileged.get_log() context['refresh_page_sec'] = 3 if context['is_busy'] else None context['version'] = __version__ @@ -210,7 +211,7 @@ class UpdateFirstbootProgressView(TemplateView): def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) context['is_busy'] = (_is_updating() - or package.is_package_manager_busy()) + or packages_privileged.is_package_manager_busy()) context['next_step'] = first_boot.next_step() context['refresh_page_sec'] = 3 if context['is_busy'] else None return context diff --git a/plinth/package.py b/plinth/package.py index fe03981e7..c4e2a80dc 100644 --- a/plinth/package.py +++ b/plinth/package.py @@ -1,14 +1,9 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Framework for installing and updating distribution packages -""" +"""Framework for installing and updating distribution packages.""" import enum -import json import logging import pathlib -import subprocess -import threading import time from typing import Optional, Union @@ -16,7 +11,8 @@ import apt.cache from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy -from plinth import actions, app +import plinth.privileged.packages as privileged +from plinth import app from plinth.errors import MissingPackageError from plinth.utils import format_lazy @@ -107,6 +103,7 @@ class Packages(app.FollowerComponent): class ConflictsAction(enum.Enum): """Action to take when a conflicting package is installed.""" + IGNORE = 'ignore' # Proceed as if there are no conflicts REMOVE = 'remove' # Remove the packages before installing the app @@ -307,74 +304,36 @@ class Transaction: """ try: - self._run_apt_command(['update']) - extra_arguments = [] - if skip_recommends: - extra_arguments.append('--skip-recommends') - - if force_configuration is not None: - extra_arguments.append( - '--force-configuration={}'.format(force_configuration)) - - if reinstall: - extra_arguments.append('--reinstall') - - if force_missing_configuration: - extra_arguments.append('--force-missing-configuration') - - self._run_apt_command(['install'] + extra_arguments + - [self.app_id] + self.package_names) - except subprocess.CalledProcessError as exception: + privileged.update() + kwargs = { + 'app_id': self.app_id, + 'packages': self.package_names, + 'skip_recommends': skip_recommends, + 'force_configuration': force_configuration, + 'reinstall': reinstall, + 'force_missing_configuration': force_missing_configuration + } + privileged.install(**kwargs) + except Exception as exception: logger.exception('Error installing package: %s', exception) raise def uninstall(self): """Run an apt-get transaction to uninstall given packages.""" try: - self._run_apt_command(['remove', self.app_id, '--packages'] + - self.package_names) - except subprocess.CalledProcessError as exception: + privileged.remove(app_id=self.app_id, packages=self.package_names) + except Exception as exception: logger.exception('Error uninstalling package: %s', exception) raise def refresh_package_lists(self): """Refresh apt package lists.""" try: - self._run_apt_command(['update']) - except subprocess.CalledProcessError as exception: + privileged.update() + except Exception as exception: logger.exception('Error updating package lists: %s', exception) raise - def _run_apt_command(self, arguments): - """Run apt-get and update progress.""" - self._reset_status() - - process = actions.superuser_run('packages', arguments, - run_in_background=True) - process.stdin.close() - - stdout_thread = threading.Thread(target=self._read_stdout, - args=(process, )) - stderr_thread = threading.Thread(target=self._read_stderr, - args=(process, )) - stdout_thread.start() - stderr_thread.start() - stdout_thread.join() - stderr_thread.join() - - return_code = process.wait() - if return_code != 0: - raise PackageException(_('Error running apt-get'), self.stderr) - - def _read_stdout(self, process): - """Read the stdout of the process and update progress.""" - for line in process.stdout: - self._parse_progress(line.decode()) - - def _read_stderr(self, process): - """Read the stderr of the process and store in buffer.""" - self.stderr = process.stderr.read().decode() - def _parse_progress(self, line): """Parse the apt-get process output line. @@ -461,10 +420,8 @@ def uninstall(package_names): def is_package_manager_busy(): """Return whether a package manager is running.""" try: - actions.superuser_run('packages', ['is-package-manager-busy'], - log_error=False) - return True - except actions.ActionError: + return privileged.is_package_manager_busy(_log_error=False) + except Exception: return False @@ -479,12 +436,8 @@ def filter_conffile_prompt_packages(packages): Information for each package includes: current_version, new_version and list of modified_conffiles. - """ - response = actions.superuser_run( - 'packages', - ['filter-conffile-packages', '--packages'] + list(packages)) - return json.loads(response) + return privileged.filter_conffile_packages(list(packages)) def packages_installed(candidates: Union[list, tuple]) -> list: diff --git a/plinth/privileged/__init__.py b/plinth/privileged/__init__.py index 82d80ca2b..14ade672b 100644 --- a/plinth/privileged/__init__.py +++ b/plinth/privileged/__init__.py @@ -1,10 +1,13 @@ # SPDX-License-Identifier: AGPL-3.0-or-later """Package holding all the privileged actions outside of apps.""" +from .packages import (filter_conffile_packages, install, + is_package_manager_busy, remove, update) from .service import (disable, enable, is_enabled, is_running, mask, reload, restart, start, stop, try_restart, unmask) __all__ = [ - 'disable', 'enable', 'is_enabled', 'is_running', 'mask', 'reload', - 'restart', 'start', 'stop', 'try_restart', 'unmask' + 'filter_conffile_packages', 'install', 'is_package_manager_busy', 'remove', + 'update', 'disable', 'enable', 'is_enabled', 'is_running', 'mask', + 'reload', 'restart', 'start', 'stop', 'try_restart', 'unmask' ] diff --git a/actions/packages b/plinth/privileged/packages.py old mode 100755 new mode 100644 similarity index 74% rename from actions/packages rename to plinth/privileged/packages.py index 8ac12a27b..76f63a764 --- a/actions/packages +++ b/plinth/privileged/packages.py @@ -1,131 +1,97 @@ -#!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Wrapper to handle package installation with apt-get. -""" +"""Wrapper to handle package installation with apt-get.""" -import argparse -import json import logging import os import subprocess -import sys from collections import defaultdict +from typing import Any, Optional import apt.cache import apt_inst import apt_pkg +from plinth import action_utils from plinth import app as app_module from plinth import module_loader -from plinth.action_utils import (apt_hold_freedombox, is_package_manager_busy, - run_apt_command) -from plinth.package import Packages +from plinth.action_utils import run_apt_command +from plinth.actions import privileged logger = logging.getLogger(__name__) -def parse_arguments(): - """Return parsed command line arguments as dictionary.""" - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') - - subparsers.add_parser('update', help='update the package lists') - - subparser = subparsers.add_parser('install', help='install packages') - subparser.add_argument( - '--skip-recommends', action='store_true', - help='whether to skip installing recommended packages') - subparser.add_argument( - '--force-configuration', choices=['new', 'old'], - help='force old/new configuration files during install') - subparser.add_argument( - '--reinstall', action='store_true', - help='force re-installation of package even if it is current') - subparser.add_argument( - '--force-missing-configuration', action='store_true', - help='force installation of missing configuration files') - subparser.add_argument( - 'app_id', help='ID of app for which package is being installed') - subparser.add_argument('packages', nargs='+', - help='list of packages to install') - - subparser = subparsers.add_parser('remove', help='remove the package(s)') - subparser.add_argument( - 'app_id', help='ID of app for which package is being uninstalled') - subparser.add_argument('--packages', required=True, - help='List of packages to remove', nargs='+') - - subparsers.add_parser('is-package-manager-busy', - help='Return whether package manager is busy') - subparser = subparsers.add_parser( - 'filter-conffile-packages', - help='Filter out packages that do not have pending conffile prompts') - subparser.add_argument('--packages', required=True, - help='List of packages to filter', nargs='+') - - subparsers.required = True - return parser.parse_args() - - -def subcommand_update(arguments): +@privileged +def update(): """Update apt package lists.""" - sys.exit(run_apt_command(['update'])) + returncode = run_apt_command(['update']) + if returncode: + raise RuntimeError( + f'Apt command failed with return code: {returncode}') -def subcommand_install(arguments): +@privileged +def install(app_id: str, packages: list[str], skip_recommends: bool = False, + force_configuration: Optional[str] = None, reinstall: bool = False, + force_missing_configuration: bool = False): """Install packages using apt-get.""" + if force_configuration not in ('old', 'new', None): + raise ValueError('Invalid value for force_configuration') + try: - _assert_managed_packages(arguments.app_id, arguments.packages) - except Exception as exception: - print('Access check failed:', exception, file=sys.stderr) - sys.exit(99) + _assert_managed_packages(app_id, packages) + except Exception: + raise PermissionError(f'Packages are not managed: {packages}') extra_arguments = [] - if arguments.skip_recommends: + if skip_recommends: extra_arguments.append('--no-install-recommends') - if arguments.force_configuration == 'old': + if force_configuration == 'old': extra_arguments += [ '-o', 'Dpkg::Options::=--force-confdef', '-o', 'Dpkg::Options::=--force-confold' ] - elif arguments.force_configuration == 'new': + elif force_configuration == 'new': extra_arguments += ['-o', 'Dpkg::Options::=--force-confnew'] - if arguments.reinstall: + if reinstall: extra_arguments.append('--reinstall') - if arguments.force_missing_configuration: + if force_missing_configuration: extra_arguments += ['-o', 'Dpkg::Options::=--force-confmiss'] subprocess.run(['dpkg', '--configure', '-a'], check=False) - with apt_hold_freedombox(): + with action_utils.apt_hold_freedombox(): run_apt_command(['--fix-broken', 'install']) - returncode = run_apt_command(['install'] + extra_arguments + - arguments.packages) + returncode = run_apt_command(['install'] + extra_arguments + packages) - sys.exit(returncode) + if returncode: + raise RuntimeError( + f'Apt command failed with return code: {returncode}') -def subcommand_remove(arguments): +@privileged +def remove(app_id: str, packages: list[str]): """Remove packages using apt-get.""" try: - _assert_managed_packages(arguments.app_id, arguments.packages) - except Exception as exception: - print('Access check failed:', exception, file=sys.stderr) - sys.exit(99) + _assert_managed_packages(app_id, packages) + except Exception: + raise PermissionError(f'Packages are not managed: {packages}') subprocess.run(['dpkg', '--configure', '-a'], check=False) - with apt_hold_freedombox(): + with action_utils.apt_hold_freedombox(): run_apt_command(['--fix-broken', 'install']) - returncode = run_apt_command(['remove'] + arguments.packages) + returncode = run_apt_command(['remove'] + packages) - sys.exit(returncode) + if returncode: + raise RuntimeError( + f'Apt command failed with return code: {returncode}') def _assert_managed_packages(app_id, packages): """Check that list of packages are in fact managed by module.""" + from plinth.package import Packages + module_loader.load_modules() app_module.apps_init() app = app_module.App.get(app_id) @@ -137,16 +103,18 @@ def _assert_managed_packages(app_id, packages): assert package in managed_packages -def subcommand_is_package_manager_busy(_): +@privileged +def is_package_manager_busy() -> bool: """Check whether package manager is busy. An exit code of zero indicates that package manager is busy. """ - if not is_package_manager_busy(): - sys.exit(-1) + return action_utils.is_package_manager_busy() -def subcommand_filter_conffile_packages(arguments): +@privileged +def filter_conffile_packages( + packages_list: list[str]) -> dict[str, dict[str, Any]]: """Return filtered list of packages which have pending conffile prompts. When considering which file needs a configuration file prompt, mimic the @@ -177,7 +145,7 @@ def subcommand_filter_conffile_packages(arguments): """ apt_pkg.init() # Read configuration that will be used later. - packages = set(arguments.packages) + packages = set(packages_list) status_hashes, current_versions = _get_conffile_hashes_from_status_file( packages) @@ -205,7 +173,7 @@ def subcommand_filter_conffile_packages(arguments): } packages_info[package] = package_info - print(json.dumps(packages_info)) + return packages_info def _get_modified_conffiles(status_hashes, mismatched_hashes, @@ -333,7 +301,7 @@ def _download_packages(packages): run_result = fetcher.run() if run_result != apt_pkg.Acquire.RESULT_CONTINUE: logger.error('Downloading packages failed.') - sys.exit(1) + raise RuntimeError('Downloading packages failed.') downloaded_files = [] for item in fetcher.items: @@ -409,16 +377,3 @@ def _get_conffile_hashes_from_downloaded_file(packages, downloaded_file, hashes[conffile] = md5sum return package_name, hashes, new_version - - -def main(): - """Parse arguments and perform all duties.""" - arguments = parse_arguments() - - subcommand = arguments.subcommand.replace('-', '_') - subcommand_method = globals()['subcommand_' + subcommand] - subcommand_method(arguments) - - -if __name__ == '__main__': - main() diff --git a/plinth/setup.py b/plinth/setup.py index 0a9449377..dddbe40bf 100644 --- a/plinth/setup.py +++ b/plinth/setup.py @@ -18,6 +18,7 @@ from plinth.signals import post_setup from . import operation as operation_module from . import package +from .privileged import packages as packages_privileged logger = logging.getLogger(__name__) @@ -418,7 +419,7 @@ class ForceUpgrader(): if _is_shutting_down: raise self.PermanentFailure('Service is shutting down') - if package.is_package_manager_busy(): + if packages_privileged.is_package_manager_busy(): raise self.TemporaryFailure('Package manager is busy') apps = self._get_list_of_apps_to_force_upgrade() From 5c5fc9eb61513a463e40bd3b1668a1e2b8d5f782 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 14 Sep 2022 08:22:23 -0700 Subject: [PATCH 72/90] actions: Drop unused superuser_run and related methods Tests: - All tests in patch series have been done with this patch applied - Unit tests pass Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- conftest.py | 20 --- doc/dev/reference/actions.rst | 2 +- plinth/actions.py | 230 +--------------------------------- plinth/errors.py | 4 - plinth/tests/test_actions.py | 160 +---------------------- 5 files changed, 3 insertions(+), 413 deletions(-) diff --git a/conftest.py b/conftest.py index 429743bef..3ba2576e8 100644 --- a/conftest.py +++ b/conftest.py @@ -148,26 +148,6 @@ def fixture_actions_module(request): return module -@pytest.fixture(name='call_action') -def fixture_call_action(request, capsys, actions_module): - """Run actions with custom root path.""" - - actions_name = getattr(request.module, 'actions_name') - - def _call_action(*args, **_kwargs): - if isinstance(args[0], list): - argv = [actions_name] + args[0] # Command line style usage - else: - argv = [args[0]] + args[1] # superuser_run style usage - - with patch('argparse._sys.argv', argv): - actions_module.main() - captured = capsys.readouterr() - return captured.out - - return _call_action - - @pytest.fixture(name='mock_privileged') def fixture_mock_privileged(request): """Mock the privileged decorator to nullify its effects.""" diff --git a/doc/dev/reference/actions.rst b/doc/dev/reference/actions.rst index 53f21c8cd..4ace1950c 100644 --- a/doc/dev/reference/actions.rst +++ b/doc/dev/reference/actions.rst @@ -13,4 +13,4 @@ else. These actions are also directly usable by a skilled administrator. The following documentation for the ``actions`` module. .. automodule:: plinth.actions - :members: run, superuser_run, run_as_user, _run, privileged + :members: privileged diff --git a/plinth/actions.py b/plinth/actions.py index 4c07205bb..b98eebab2 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -1,79 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -"""Run specified actions. - -Actions run commands with this contract (version 1.1): - -1. (promise) Super-user actions run as root. Normal actions do not. - -2. (promise) The actions directory can't be changed at run time. - - This guarantees that we can only select from the correct set of actions. - -3. (restriction) Only specifically allowed actions can run. - - A. Scripts in a directory above the actions directory can't be run. - - Arguments (and options) can't coerce the system to run actions in - directories above the actions directory. - - Arguments that fail this validation will raise a ValueError. - - B. Scripts in a directory beneath the actions directory can't be run. - - Arguments (and options) can't coerce the system to run actions in - sub-directories of the actions directory. - - (An important side-effect of this is that the system will not try to - follow symlinks to other action directories.) - - Arguments that fail this validation will raise a ValueError. - - C. Only one action can be called at a time. - - This prevents us from appending multiple (unexpected) actions to - the call. Any special shell characters in the action name will - simply be treated as the action itself when trying to search for - an action. The action will then not be found. - - $ action="echo '$options'; echo 'oops'" - $ options="hi" - $ $action # oops, the file system is gone! - - Arguments that fail this validation will raise a ValueError. - - D. Options can't be used to run other actions: - - $ action="echo '$options'" - $ options="hi'; rm -rf /;'" - $ $action # oops, the file system is gone! - - Any option that tries to include special shell characters will - simply be treated as an option with special characters and will - not be interpreted by the shell. - - Any call wishing to include special shell characters in options - list does not need to escape them. They are taken care of. The - option string is passed to the action exactly as it is passed in. - - E. Actions must exist in the actions directory. - -4. (promise) Options are passed as arguments to the action. - - Options can be provided as a list or as a tuple. - -5. (promise) Output is returned from the command. In case of an - error, ActionError is raised with action, output and error strings - as arguments. - -6. (limitation) Providing the process with input is not possible. - - Don't expect to give the process additional input after it's started. Any - interaction with the spawned process must be carried out through some other - method (maybe the process opens a socket, or something). - -7. Option - -""" +"""Framework to run specified actions with elevated privileges.""" import functools import importlib @@ -81,168 +7,14 @@ import inspect import json import logging import os -import re -import shlex import subprocess import threading from plinth import cfg -from plinth.errors import ActionError logger = logging.getLogger(__name__) -def run(action, options=None, input=None, run_in_background=False): - """Safely run a specific action as the current user. - - See actions._run for more information. - """ - return _run(action, options, input, run_in_background, False) - - -def superuser_run(action, options=None, input=None, run_in_background=False, - log_error=True): - """Safely run a specific action as root. - - See actions._run for more information. - """ - return _run(action, options, input, run_in_background, True, - log_error=log_error) - - -def run_as_user(action, options=None, input=None, run_in_background=False, - become_user=None): - """Run a command as a different user. - - If become_user is None, run as current user. - """ - return _run(action, options, input, run_in_background, False, become_user) - - -def _run(action, options=None, input=None, run_in_background=False, - run_as_root=False, become_user=None, log_error=True): - """Safely run a specific action as a normal user or root. - - Actions are pulled from the actions directory. - - - options are added to the action command. - - - input: data (as bytes) that will be sent to the action command's stdin. - - - run_in_background: run asynchronously or wait for the command to - complete. - - - run_as_root: execute the command through sudo. - - """ - if options is None: - options = [] - - # Contract 3A and 3B: don't call anything outside of the actions directory. - if os.sep in action: - raise ValueError('Action cannot contain: ' + os.sep) - - cmd = os.path.join(cfg.actions_dir, action) - if not os.path.realpath(cmd).startswith(cfg.actions_dir): - raise ValueError('Action has to be in directory %s' % cfg.actions_dir) - - # Contract 3C: interpret shell escape sequences as literal file names. - # Contract 3E: fail if the action doesn't exist or exists elsewhere. - if not os.access(cmd, os.F_OK): - raise ValueError('Action must exist in action directory.') - - cmd = [cmd] - - # Contract: 3C, 3D: don't allow shell special characters in - # options be interpreted by the shell. When using - # subprocess.Popen with list invocation and not shell invocation, - # escaping is unnecessary as each argument is passed directly to - # the command and not parsed by a shell. - if options: - if not isinstance(options, (list, tuple)): - raise ValueError('Options must be list or tuple.') - - cmd += list(options) # No escaping necessary - - # Contract 1: commands can run via sudo. - sudo_call = [] - if run_as_root: - sudo_call = ['sudo', '-n'] - elif become_user: - sudo_call = ['sudo', '-n', '-u', become_user] - - if cfg.develop and sudo_call: - # Passing 'env' does not work with sudo, so append the PYTHONPATH - # as part of the command - sudo_call += ['PYTHONPATH=%s' % cfg.file_root] - - if sudo_call: - cmd = sudo_call + cmd - - _log_command(cmd) - - # Contract 3C: don't interpret shell escape sequences. - # Contract 5 (and 6-ish). - kwargs = { - 'stdin': subprocess.PIPE, - 'stdout': subprocess.PIPE, - 'stderr': subprocess.PIPE, - 'shell': False, - } - if cfg.develop: - # In development mode pass on local pythonpath to access Plinth - kwargs['env'] = {'PYTHONPATH': cfg.file_root} - - proc = subprocess.Popen(cmd, **kwargs) - - if not run_in_background: - output, error = proc.communicate(input=input) - output, error = output.decode(), error.decode() - if proc.returncode != 0: - if log_error: - logger.error('Error executing command - %s, %s, %s', cmd, - output, error) - raise ActionError(action, output, error) - - return output - - return proc - - -def _log_command(cmd): - """Log a command with special pretty formatting to catch the eye.""" - cmd = list(cmd) # Make a copy of the command not to affect the original - - prompt = '$' - user = '' - if cmd and cmd[0] == 'sudo': - cmd = cmd[1:] - prompt = '#' - - # Drop -n argument to sudo - if cmd and cmd[0] == '-n': - cmd = cmd[1:] - - # Capture username separately - if len(cmd) > 1 and cmd[0] == '-u': - prompt = '$' - user = cmd[1] - cmd = cmd[2:] - - # Drop environmental variables set via sudo - while cmd and re.match(r'.*=.*', cmd[0]): - cmd = cmd[1:] - - # Strip the command's prefix - if cmd: - cmd[0] = cmd[0].split('/')[-1] - - # Shell escape and join command arguments - cmd = ' '.join([shlex.quote(part) for part in cmd]) - - logger.info('%s%s %s', user, prompt, cmd) - - def privileged(func): """Mark a method as allowed to be run as privileged method. diff --git a/plinth/errors.py b/plinth/errors.py index 32d4387f8..4c6bcaeba 100644 --- a/plinth/errors.py +++ b/plinth/errors.py @@ -8,10 +8,6 @@ class PlinthError(Exception): """Base class for all FreedomBox specific errors.""" -class ActionError(PlinthError): - """Use this error for exceptions when executing an action.""" - - class PackageNotInstalledError(PlinthError): """Could not complete module setup due to missing package.""" diff --git a/plinth/tests/test_actions.py b/plinth/tests/test_actions.py index ed76581a2..ed37a750e 100644 --- a/plinth/tests/test_actions.py +++ b/plinth/tests/test_actions.py @@ -9,17 +9,13 @@ description of the expectations. import json import os -import pathlib -import shutil import subprocess -import tempfile from unittest.mock import Mock, call, patch import pytest from plinth import cfg -from plinth.actions import _log_command as log_command -from plinth.actions import privileged, run, superuser_run +from plinth.actions import privileged @pytest.fixture(name='popen') @@ -44,160 +40,6 @@ def fixture_popen(): yield popen -@pytest.fixture(autouse=True) -def actions_test_setup(load_cfg): - """Setup a temporary directory for testing actions. - - Copy system commands ``echo`` and ``id`` into actions directory during - testing. - - """ - with tempfile.TemporaryDirectory() as tmp_directory: - old_actions_dir = cfg.actions_dir - cfg.actions_dir = str(tmp_directory) - - actions_dir = pathlib.Path(__file__).parent / '../../actions' - shutil.copy(str(actions_dir / 'test_path'), str(tmp_directory)) - shutil.copy('/bin/echo', str(tmp_directory)) - shutil.copy('/usr/bin/id', str(tmp_directory)) - - yield - cfg.actions_dir = old_actions_dir - - -def notest_run_as_root(): - """1. Privileged actions run as root. """ - assert superuser_run('id', ['-ur'])[0].strip() == '0' # user 0 is root - - -def test_breakout_actions_dir(): - """2. The actions directory can't be changed at run time. - - Can't currently be tested, as the actions directory is hardcoded. - """ - - -def test_breakout_up(): - """3A. Users can't call actions above the actions directory. - - Tests both a relative and a literal path. - """ - for action in ('../echo', '/bin/echo'): - with pytest.raises(ValueError): - run(action, ['hi']) - - -def test_breakout_down(): - """3B. Users can't call actions beneath the actions directory.""" - action = 'directory/echo' - with pytest.raises(ValueError): - superuser_run(action) - - -def test_breakout_actions(): - """3C. Actions can't be used to run other actions. - - If multiple actions are specified, bail out. - """ - # Counting is safer than actual badness. - actions = ('echo ""; echo $((1+1))', 'echo "" && echo $((1+1))', - 'echo "" || echo $((1+1))') - options = ('good', '') - - for action in actions: - for option in options: - with pytest.raises(ValueError): - run(action, [option]) - - -def test_breakout_option_string(): - """3D. Option strings can't be used to run other actions. - - Verify that shell control characters aren't interpreted. - """ - options = ('; echo hello', '&& echo hello', '|| echo hello', - '& echo hello', r'\; echo hello', '| echo hello', - r':;!&\/$%@`"~#*(){}[]|+=') - for option in options: - output = run('echo', [option]) - output = output.rstrip('\n') - assert option == output - - -def test_breakout_option_list(): - """3D. Option lists can't be used to run other actions. - - Verify that shell control characters aren't interpreted in - option lists. - """ - option_lists = ( - (';', 'echo', 'hello'), - ('&&', 'echo', 'hello'), - ('||', 'echo', 'hello'), - ('&', 'echo', 'hello'), - (r'\;', 'echo' - 'hello'), - ('|', 'echo', 'hello'), - ('', 'echo', '', 'hello'), # Empty option argument - tuple(r':;!&\/$%@`"~#*(){}[]|+=')) - for options in option_lists: - output = run('echo', options) - output = output.rstrip('\n') - expected_output = ' '.join(options) - assert output == expected_output - - -def test_multiple_options_and_output(): - """4. Multiple options can be provided as a list or as a tuple. - - 5. Output is returned from the command. - """ - options = '1 2 3 4 5 6 7 8 9' - - output = run('echo', options.split()) - output = output.rstrip('\n') - assert options == output - - output = run('echo', tuple(options.split())) - output = output.rstrip('\n') - assert options == output - - -@pytest.mark.usefixtures('develop_mode', 'needs_root') -def test_action_path(monkeypatch): - """Test that in development mode, python action scripts get the - correct PYTHONPATH""" - monkeypatch.setitem(os.environ, 'PYTHONPATH', '') - plinth_path = run('test_path').strip() - su_plinth_path = superuser_run('test_path').strip() - assert plinth_path.startswith(cfg.file_root) - assert plinth_path == su_plinth_path - - -@patch('plinth.actions.logger.info') -@pytest.mark.parametrize('cmd,message', [ - [['ls'], '$ ls'], - [['/bin/ls'], '$ ls'], - [['ls', 'a', 'b', 'c'], '$ ls a b c'], - [['ls', 'a b c'], "$ ls 'a b c'"], - [['ls', 'a;'], "$ ls 'a;'"], - [['sudo', 'ls'], '# ls'], - [['sudo', '-n', 'ls'], '# ls'], - [['sudo', '-u', 'tester', 'ls'], 'tester$ ls'], - [['sudo', 'key1=value1', 'key2=value2', 'ls'], '# ls'], - [[ - 'sudo', '-n', 'PYTHONPATH=/vagrant', '/vagrant/actions/ejabberd', - 'add-domain', '--domainname', 'freedombox.local' - ], '# ejabberd add-domain --domainname freedombox.local'], -]) -def test_log_command(logger, cmd, message): - """Test log messages for various action calls.""" - log_command(cmd) - logger.assert_called_once() - args = logger.call_args[0] - assert message == args[0] % args[1:] - - def test_privileged_properties(): """Test that privileged decorator sets proper properties on the method.""" From 65c433a2112641d3b3ac87a34c44d8d59db0683a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 15 Sep 2022 07:43:19 -0700 Subject: [PATCH 73/90] action_utils: Drop unused progress requests from apt-get Tests: - All tests in patch series have been done with this patch applied - Install and uninstall of apps works Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/action_utils.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/plinth/action_utils.py b/plinth/action_utils.py index ffaad50d1..3247fb90c 100644 --- a/plinth/action_utils.py +++ b/plinth/action_utils.py @@ -405,21 +405,12 @@ def is_disk_image(): def run_apt_command(arguments): """Run apt-get with provided arguments.""" - # Ask apt-get to output its progress to file descriptor 3. - command = [ - 'apt-get', '--assume-yes', '--quiet=2', '--option', 'APT::Status-Fd=3' - ] + arguments + command = ['apt-get', '--assume-yes', '--quiet=2'] + arguments - # Duplicate stdout to file descriptor 3 for this process. - os.dup2(1, 3) - - # Pass on file descriptor 3 instead of closing it. Close stdout - # so that regular output is ignored. env = os.environ.copy() env['DEBIAN_FRONTEND'] = 'noninteractive' process = subprocess.run(command, stdin=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, close_fds=False, - env=env, check=False) + stdout=subprocess.DEVNULL, env=env, check=False) return process.returncode From 158366feeab54af92d3d1220868aa24b732b63b8 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 19 Sep 2022 07:14:32 -0700 Subject: [PATCH 74/90] bind: Drop enabling DNSSEC (deprecated) as it is always enabled - As of bind 9.16, the option to enable DNSSEC 'dnssec-enable' is obsolete and has no effect[1]. The option 'dnssec-validation' controls DNSSEC validation and is set to 'auto' by default. 'auto' means that DNSSEC validation is enabled and default trust anchor is used for DNS root zone. DNSSEC signatures are also passed onto a client whenever available. Current stable, Debian Buster, has version 9.16[3]. - As of bind 9.18, the option to enable DNSSEC 'dnssec-enable' is not recognized and causes the daemon to fail to start[2]. Debian next, Debian Bookworm, has version 9.18[3]. Therefore, in testing and unstable, bind fails to start of installation from FreedomBox. - There is no use-case for changing the current default behavior. Links: 1) https://bind9.readthedocs.io/en/v9_16_32/reference.html#dnssec-validation-option 2) https://bind9.readthedocs.io/en/v9_18_6/reference.html 3) https://tracker.debian.org/pkg/bind9 Tests: - Run functional and unit tests. - Option to enable/disable DNSSEC is removed. - When bind is installed on testing without the patch, it fails to start. When the patch is applied, bind will be upgraded, the dnssec-enable option is removed from the configuration file /etc/bind/named.conf.options and bind is running. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/bind/__init__.py | 2 +- plinth/modules/bind/forms.py | 11 ++---- plinth/modules/bind/privileged.py | 37 +++++--------------- plinth/modules/bind/tests/test_bind.py | 12 ------- plinth/modules/bind/tests/test_functional.py | 31 ---------------- plinth/modules/bind/views.py | 5 ++- 6 files changed, 15 insertions(+), 83 deletions(-) diff --git a/plinth/modules/bind/__init__.py b/plinth/modules/bind/__init__.py index 326b64086..fe2f114a5 100644 --- a/plinth/modules/bind/__init__.py +++ b/plinth/modules/bind/__init__.py @@ -30,7 +30,7 @@ class BindApp(app_module.App): app_id = 'bind' - _version = 2 + _version = 3 def __init__(self): """Create components for the app.""" diff --git a/plinth/modules/bind/forms.py b/plinth/modules/bind/forms.py index 36cca46cc..95e87407e 100644 --- a/plinth/modules/bind/forms.py +++ b/plinth/modules/bind/forms.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Forms for BIND module. -""" +"""Forms for BIND module.""" from django import forms from django.core.validators import validate_ipv46_address @@ -15,12 +13,9 @@ def validate_ips(ips): class BindForm(forms.Form): - """BIND configuration form""" + """BIND configuration form.""" + forwarders = forms.CharField( label=_('Forwarders'), required=False, validators=[validate_ips], help_text=_('A list DNS servers, separated by space, to which ' 'requests will be forwarded')) - - enable_dnssec = forms.BooleanField( - label=_('Enable DNSSEC'), required=False, - help_text=_('Enable Domain Name System Security Extensions')) diff --git a/plinth/modules/bind/privileged.py b/plinth/modules/bind/privileged.py index 562ee5199..0e1713229 100644 --- a/plinth/modules/bind/privileged.py +++ b/plinth/modules/bind/privileged.py @@ -28,9 +28,6 @@ forwarders { }; forward first; -dnssec-enable yes; -dnssec-validation auto; - auth-nxdomain no; # conform to RFC1035 listen-on-v6 { any; }; }; @@ -43,6 +40,8 @@ def setup(old_version: int): if old_version == 0: with open(CONFIG_FILE, 'w', encoding='utf-8') as conf_file: conf_file.write(DEFAULT_CONFIG) + elif old_version < 3: + _remove_dnssec() Path(ZONES_DIR).mkdir(exist_ok=True, parents=True) @@ -50,10 +49,9 @@ def setup(old_version: int): @privileged -def configure(forwarders: str, dnssec: bool): +def configure(forwarders: str): """Configure BIND.""" _set_forwarders(forwarders) - _set_dnssec(dnssec) action_utils.service_restart('named') @@ -62,22 +60,15 @@ def get_config(): data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] forwarders = '' - dnssec_enabled = False flag = False for line in data: if re.match(r'^\s*forwarders\s+{', line): flag = True - elif re.match(r'^\s*dnssec-enable\s+yes;', line): - dnssec_enabled = True elif flag and '//' not in line: forwarders = re.sub('[;]', '', line) flag = False - conf = { - 'forwarders': forwarders, - 'enable_dnssec': dnssec_enabled, - } - return conf + return {'forwarders': forwarders} def _set_forwarders(forwarders): @@ -100,24 +91,14 @@ def _set_forwarders(forwarders): conf_file.close() -def _set_dnssec(choice): - """Enable or disable DNSSEC.""" +def _remove_dnssec(): + """Remove DNSSEC options.""" data = [line.strip() for line in open(CONFIG_FILE, 'r', encoding='utf-8')] - if choice: - conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') + with open(CONFIG_FILE, 'w', encoding='utf-8') as file_handle: for line in data: - if re.match(r'//\s*dnssec-enable\s+yes;', line): - line = line.lstrip('/') - conf_file.write(line + '\n') - conf_file.close() - else: - conf_file = open(CONFIG_FILE, 'w', encoding='utf-8') - for line in data: - if re.match(r'^\s*dnssec-enable\s+yes;', line): - line = '//' + line - conf_file.write(line + '\n') - conf_file.close() + if not re.match(r'^\s*dnssec-enable\s+yes;', line): + file_handle.write(line + '\n') def get_served_domains(): diff --git a/plinth/modules/bind/tests/test_bind.py b/plinth/modules/bind/tests/test_bind.py index 465fd3781..6131893a9 100644 --- a/plinth/modules/bind/tests/test_bind.py +++ b/plinth/modules/bind/tests/test_bind.py @@ -74,18 +74,6 @@ def test_set_forwarders(): assert conf['forwarders'] == '' -@pytest.mark.usefixtures('configuration_file') -def test_enable_dnssec(): - """Test that enabling DNSSEC works.""" - bind.privileged._set_dnssec(True) - conf = bind.privileged.get_config() - assert conf['enable_dnssec'] - - bind.privileged._set_dnssec(False) - conf = bind.privileged.get_config() - assert not conf['enable_dnssec'] - - @pytest.mark.usefixtures('bind_zones_folder') def test_get_correct_served_domains(): """ diff --git a/plinth/modules/bind/tests/test_functional.py b/plinth/modules/bind/tests/test_functional.py index fc43e6ab6..99f2c1e0c 100644 --- a/plinth/modules/bind/tests/test_functional.py +++ b/plinth/modules/bind/tests/test_functional.py @@ -23,45 +23,14 @@ class TestBindApp(functional.BaseAppTests): functional.set_forwarders(session_browser, '1.1.1.1 1.0.0.1') assert functional.get_forwarders(session_browser) == '1.1.1.1 1.0.0.1' - def test_enable_disable_dnssec(self, session_browser): - """Test enabling/disabling DNSSEC.""" - functional.app_enable(session_browser, 'bind') - _enable_dnssec(session_browser, False) - - _enable_dnssec(session_browser, True) - assert _get_dnssec(session_browser) - - _enable_dnssec(session_browser, False) - assert not _get_dnssec(session_browser) - @pytest.mark.backups def test_backup_restore(self, session_browser): """Test backup and restore.""" functional.app_enable(session_browser, 'bind') functional.set_forwarders(session_browser, '1.1.1.1') - _enable_dnssec(session_browser, False) functional.backup_create(session_browser, 'bind', 'test_bind') functional.set_forwarders(session_browser, '1.0.0.1') - _enable_dnssec(session_browser, True) functional.backup_restore(session_browser, 'bind', 'test_bind') assert functional.get_forwarders(session_browser) == '1.1.1.1' - assert not _get_dnssec(session_browser) - - -def _enable_dnssec(browser, enable): - """Enable/disable DNSSEC in bind configuration.""" - functional.nav_to_module(browser, 'bind') - if enable: - browser.check('enable_dnssec') - else: - browser.uncheck('enable_dnssec') - - functional.submit(browser, form_class='form-configuration') - - -def _get_dnssec(browser): - """Return whether DNSSEC is enabled/disabled in bind configuration.""" - functional.nav_to_module(browser, 'bind') - return browser.find_by_name('enable_dnssec').first.checked diff --git a/plinth/modules/bind/views.py b/plinth/modules/bind/views.py index 20ab92e85..d5de97387 100644 --- a/plinth/modules/bind/views.py +++ b/plinth/modules/bind/views.py @@ -56,9 +56,8 @@ class BindAppView(AppView): # pylint: disable=too-many-ancestors data = form.cleaned_data old_config = privileged.get_config() - if old_config['forwarders'] != data['forwarders'] \ - or old_config['enable_dnssec'] != data['enable_dnssec']: - privileged.configure(data['forwarders'], data['enable_dnssec']) + if old_config['forwarders'] != data['forwarders']: + privileged.configure(data['forwarders']) messages.success(self.request, _('Configuration updated')) return super().form_valid(form) From e3a67da8ec7012286a7cadce30f7f94730c4f8a8 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 19 Sep 2022 11:30:06 -0700 Subject: [PATCH 75/90] config: Drop legacy migration of Apache homepage settings - Initial implementation of home page setting used the file /etc/apache2/conf-available/freedombox.conf and edited the file. Since this file is shipped by the freedombox package, it lead to package getting stuck with conf-file prompt. FreedomBox v19.10 first fix this by carefully undoing the edits in this file and making them elsewhere. - This fix is present in Debian present old stable (with backports) and current stable, the migration is not needed in almost all the of cases. Tests: - First setup of FreedomBox works. - Setting home page works are expected. - Functional tests for config module works. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/config/__init__.py | 23 +++-------------------- plinth/modules/config/privileged.py | 24 ------------------------ 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/plinth/modules/config/__init__.py b/plinth/modules/config/__init__.py index 9910c6798..b3ee55574 100644 --- a/plinth/modules/config/__init__.py +++ b/plinth/modules/config/__init__.py @@ -76,7 +76,6 @@ class ConfigApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - _migrate_home_page_config() if old_version <= 3: privileged.set_logging_mode('volatile') @@ -148,8 +147,9 @@ def _home_page_scid2url(shortcut_id): return url -def _get_home_page_url(conf_file): +def _get_home_page_url(): """Get the default application for the domain.""" + conf_file = privileged.APACHE_HOMEPAGE_CONFIG aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') @@ -168,11 +168,7 @@ def _get_home_page_url(conf_file): def get_home_page(): """Return the shortcut ID that is set as current home page.""" - CONF_FILE = privileged.APACHE_HOMEPAGE_CONFIG if os.path.exists( - privileged.APACHE_HOMEPAGE_CONFIG - ) else privileged.FREEDOMBOX_APACHE_CONFIG - - url = _get_home_page_url(CONF_FILE) + url = _get_home_page_url() return home_page_url2scid(url) @@ -196,16 +192,3 @@ def set_advanced_mode(advanced_mode): """Turn on/off advanced mode.""" from plinth import kvstore kvstore.set(ADVANCED_MODE_KEY, advanced_mode) - - -def _migrate_home_page_config(): - """Move the home page configuration to an external file.""" - # Hold the current home page in a variable - home_page = get_home_page() - - # Reset the home page to plinth in freedombox.conf - privileged.reset_home_page() - - # Write the home page setting into the new conf file - # This step is run at the end because it reloads the Apache server - change_home_page(home_page) diff --git a/plinth/modules/config/privileged.py b/plinth/modules/config/privileged.py index 8dd170975..24d38de49 100644 --- a/plinth/modules/config/privileged.py +++ b/plinth/modules/config/privileged.py @@ -15,8 +15,6 @@ APACHE_CONF_ENABLED_DIR = '/etc/apache2/conf-enabled' APACHE_HOMEPAGE_CONF_FILE_NAME = 'freedombox-apache-homepage.conf' APACHE_HOMEPAGE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, APACHE_HOMEPAGE_CONF_FILE_NAME) -FREEDOMBOX_APACHE_CONFIG = os.path.join(APACHE_CONF_ENABLED_DIR, - 'freedombox.conf') JOURNALD_FILE = pathlib.Path('/etc/systemd/journald.conf.d/50-freedombox.conf') @@ -115,25 +113,3 @@ def set_home_page(homepage: str): conf_file.write(redirect_rule) action_utils.webserver_enable('freedombox-apache-homepage') - - -@privileged -def reset_home_page(): - """Set the Apache web server's home page to the default - /plinth.""" - config_file = FREEDOMBOX_APACHE_CONFIG - default_path = 'plinth' - - aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + - augeas.Augeas.NO_MODL_AUTOLOAD) - aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') - aug.set('/augeas/load/Httpd/incl[last() + 1]', config_file) - aug.load() - - aug.defvar('conf', '/files' + config_file) - - for match in aug.match('/files' + config_file + - '/directive["RedirectMatch"]'): - if aug.get(match + "/arg[1]") == '''"^/$"''': - aug.set(match + "/arg[2]", '"/{}"'.format(default_path)) - - aug.save() From 6a0493a75282ad7b9de2f4fae68dce255d5bd951 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 7 Oct 2022 01:18:37 -0700 Subject: [PATCH 76/90] action_utils: Drop support for non-systemd environments - There hasn't been a need for this for a long time. non-systemd environments haven't been worked on or tested for in a long time. - Keep the is_systemd_running() method for future use. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/action_utils.py | 17 ++++------------- plinth/modules/calibre/tests/test_privileged.py | 2 +- .../modules/ejabberd/tests/test_turn_config.py | 2 +- .../matrixsynapse/tests/test_turn_config.py | 6 ++++-- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/plinth/action_utils.py b/plinth/action_utils.py index 3247fb90c..c3d6945f9 100644 --- a/plinth/action_utils.py +++ b/plinth/action_utils.py @@ -39,13 +39,8 @@ def service_is_running(servicename): Does not need to run as root. """ try: - if is_systemd_running(): - subprocess.run(['systemctl', 'status', servicename], check=True, - stdout=subprocess.DEVNULL) - else: - subprocess.run(['service', servicename, 'status'], check=True, - stdout=subprocess.DEVNULL) - + subprocess.run(['systemctl', 'status', servicename], check=True, + stdout=subprocess.DEVNULL) return True except subprocess.CalledProcessError: # If a service is not running we get a status code != 0 and @@ -126,12 +121,8 @@ def service_reload(service_name): def service_action(service_name, action): """Perform the given action on the service_name.""" - if is_systemd_running(): - subprocess.run(['systemctl', action, service_name], - stdout=subprocess.DEVNULL, check=False) - else: - subprocess.run(['service', service_name, action], - stdout=subprocess.DEVNULL, check=False) + subprocess.run(['systemctl', action, service_name], + stdout=subprocess.DEVNULL, check=False) def webserver_is_enabled(name, kind='config'): diff --git a/plinth/modules/calibre/tests/test_privileged.py b/plinth/modules/calibre/tests/test_privileged.py index 2b85f3eab..6b41173f8 100644 --- a/plinth/modules/calibre/tests/test_privileged.py +++ b/plinth/modules/calibre/tests/test_privileged.py @@ -30,7 +30,7 @@ def fixture_patch(): path.touch() with patch('subprocess.call') as subprocess_call, \ - patch('shutil.chown'): + patch('subprocess.run'), patch('shutil.chown'): subprocess_call.side_effect = side_effect yield diff --git a/plinth/modules/ejabberd/tests/test_turn_config.py b/plinth/modules/ejabberd/tests/test_turn_config.py index 564418a5e..f88618c47 100644 --- a/plinth/modules/ejabberd/tests/test_turn_config.py +++ b/plinth/modules/ejabberd/tests/test_turn_config.py @@ -66,7 +66,7 @@ def fixture_test_configuration(conf_file): def _set_turn_configuration(config=managed_configuration, managed=True): - with patch('plinth.privileged.service.is_running', return_value=False): + with patch('plinth.action_utils.service_is_running', return_value=False): ejabberd.update_turn_configuration(config, managed=managed) diff --git a/plinth/modules/matrixsynapse/tests/test_turn_config.py b/plinth/modules/matrixsynapse/tests/test_turn_config.py index 9a5f7b961..9971e070b 100644 --- a/plinth/modules/matrixsynapse/tests/test_turn_config.py +++ b/plinth/modules/matrixsynapse/tests/test_turn_config.py @@ -72,12 +72,14 @@ updated_coturn_configuration = TurnConfiguration( def _set_managed_configuration(config=coturn_configuration): - matrixsynapse.update_turn_configuration(config) + with patch('plinth.action_utils.service_try_restart'): + matrixsynapse.update_turn_configuration(config) def _set_overridden_configuration( config=overridden_configuration): - matrixsynapse.update_turn_configuration(config, managed=False) + with patch('plinth.action_utils.service_try_restart'): + matrixsynapse.update_turn_configuration(config, managed=False) def _assert_conf(expected_configuration, expected_managed): From 72d7a05eada279a83ecf2bbb09d7514615b10801 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 22 Sep 2022 17:20:48 -0700 Subject: [PATCH 77/90] apache: Fix logs still going into /var/log files Closes: #2264. - Set apache-auth fail2ban jail's backend to read from journal instead of syslog. Tweak the regex matching to deal with the custom format. - Adjust the apache error log format to remove unnecessary timestamp. It causes problems for fail2ban regex matching. - There was an error in the earlier patch the make apache log into journald. Configuration for TLS sites still contained ErrorLog and CustomLog directives. Remove them. - There is also file with CustomLog directive that logs for other vhosts. - For some reason, for custom error log format, %T - thread ID did not work and had to switch to %{g}T global thread ID. - Added journalmatch to improve performance by matching the regular expressions against only specific journal entries. Tests: - In a container, apply the patch, run setup and start FreedomBox. Apache app is updated to new version. Apache web server is reloaded. The other-vhosts-access-log configuration is disabled. - On a production machine, remove the directives in freedombox-tls-site-macro.conf and disabling other-vhosts-access-log stopped the logging into /var/log/apache2/ directory. - Use TTRSS /tt-rss-app/ URL and type wrong credentials for 10 times. The client is banned for 10 minutes. Repeat after unban. Client is banned again. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- .../apache2/conf-available/freedombox-tls-site-macro.conf | 3 --- data/etc/apache2/conf-available/freedombox.conf | 3 +++ plinth/modules/apache/__init__.py | 2 +- .../data/etc/fail2ban/jail.d/apache-auth-freedombox.conf | 5 ++++- plinth/modules/apache/privileged.py | 3 +++ 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/data/etc/apache2/conf-available/freedombox-tls-site-macro.conf b/data/etc/apache2/conf-available/freedombox-tls-site-macro.conf index 9f8389408..0eecd13ed 100644 --- a/data/etc/apache2/conf-available/freedombox-tls-site-macro.conf +++ b/data/etc/apache2/conf-available/freedombox-tls-site-macro.conf @@ -7,9 +7,6 @@ ServerName $domain DocumentRoot /var/www/html - ErrorLog ${APACHE_LOG_DIR}/error.log - CustomLog ${APACHE_LOG_DIR}/access.log combined - SSLEngine on # Disable TLS1.1 and below. Client support: Firefox: 27, Android: diff --git a/data/etc/apache2/conf-available/freedombox.conf b/data/etc/apache2/conf-available/freedombox.conf index d493cc0de..95023151d 100644 --- a/data/etc/apache2/conf-available/freedombox.conf +++ b/data/etc/apache2/conf-available/freedombox.conf @@ -145,4 +145,7 @@ RedirectMatch "^/$" "/plinth" ## journalctl --identifier apache-error --output cat > error.log ## ErrorLog "|/usr/bin/systemd-cat --identifier=apache-error" +# Remove timestamp at the beginning from the default log format. journald +# records its own timestamp. +ErrorLogFormat "[%-m:%l] [pid %P:tid %{g}T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i" CustomLog "|/usr/bin/systemd-cat --identifier=apache-access" vhost_combined diff --git a/plinth/modules/apache/__init__.py b/plinth/modules/apache/__init__.py index 9d78c1e99..c0dffcae3 100644 --- a/plinth/modules/apache/__init__.py +++ b/plinth/modules/apache/__init__.py @@ -21,7 +21,7 @@ class ApacheApp(app_module.App): app_id = 'apache' - _version = 10 + _version = 11 def __init__(self): """Create components for the app.""" diff --git a/plinth/modules/apache/data/etc/fail2ban/jail.d/apache-auth-freedombox.conf b/plinth/modules/apache/data/etc/fail2ban/jail.d/apache-auth-freedombox.conf index 9e20fb6dc..25a0c8335 100644 --- a/plinth/modules/apache/data/etc/fail2ban/jail.d/apache-auth-freedombox.conf +++ b/plinth/modules/apache/data/etc/fail2ban/jail.d/apache-auth-freedombox.conf @@ -1,3 +1,6 @@ [apache-auth] enabled = true -backend = auto +# Tweak the filter regex to work with journal format. Use apache-error as the +# syslog facility +filter = apache-auth[logtype="journal",logging="syslog",_daemon="apache-error"] +journalmatch = SYSLOG_IDENTIFIER=apache-error diff --git a/plinth/modules/apache/privileged.py b/plinth/modules/apache/privileged.py index 3e0f35e26..812df5c1f 100644 --- a/plinth/modules/apache/privileged.py +++ b/plinth/modules/apache/privileged.py @@ -89,6 +89,9 @@ def setup(old_version: int): webserver.enable('rewrite', kind='module') webserver.enable('macro', kind='module') + # Disable logging into files, use FreedomBox configured systemd logging + webserver.disable('other-vhosts-access-log', kind='config') + # Disable /server-status page to avoid leaking private info. webserver.disable('status', kind='module') From 9cc91441ff02e0f2242b4da2395dfab3220df26b Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 28 Sep 2022 15:05:10 -0700 Subject: [PATCH 78/90] wordpress: Update fail2ban filter - Name of the jail has to be less than 29 characters for an iptables/nft chain to be created. - Make the regular expressions more specific to avoid matching incorrect fields for . - Added journalmatch to improve performance by matching the regular expressions against only specific journal entries. Tests: - Run setup.py, remove the old jail and filter files. Restart fail2ban and make 10 incorrect login attempts. The IP address gets banned for 10 minutes. - Not run: Build new freedombox package and upgrade from older version to see that old configuration files have been removed. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- debian/freedombox.maintscript | 2 ++ .../etc/fail2ban/filter.d/wordpress-auth-freedombox.conf | 2 -- .../data/etc/fail2ban/filter.d/wordpress-freedombox.conf | 7 +++++++ .../etc/fail2ban/jail.d/wordpress-auth-freedombox.conf | 3 --- .../data/etc/fail2ban/jail.d/wordpress-freedombox.conf | 4 ++++ 5 files changed, 13 insertions(+), 5 deletions(-) delete mode 100644 plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-auth-freedombox.conf create mode 100644 plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-freedombox.conf delete mode 100644 plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-auth-freedombox.conf create mode 100644 plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-freedombox.conf diff --git a/debian/freedombox.maintscript b/debian/freedombox.maintscript index 49e3fb9ac..8f0d298fc 100644 --- a/debian/freedombox.maintscript +++ b/debian/freedombox.maintscript @@ -21,3 +21,5 @@ rm_conffile /etc/plinth/modules-enabled/mldonkey 22.4~ rm_conffile /etc/apache2/conf-available/mldonkey-freedombox.conf 22.4~ rm_conffile /etc/apache2/sites-available/plinth.conf 22.16~ rm_conffile /etc/apache2/sites-available/plinth-ssl.conf 22.16~ +rm_conffile /etc/fail2ban/jail.d/wordpress-auth-freedombox.conf 22.22~ +rm_conffile /etc/fail2ban/filter.d/wordpress-auth-freedombox.conf 22.22~ diff --git a/plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-auth-freedombox.conf b/plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-auth-freedombox.conf deleted file mode 100644 index 6942f7502..000000000 --- a/plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-auth-freedombox.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Definition] -failregex = .* .* "POST /wordpress/wp-login.php HTTP/\S+" 200 diff --git a/plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-freedombox.conf b/plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-freedombox.conf new file mode 100644 index 000000000..44403b5eb --- /dev/null +++ b/plinth/modules/wordpress/data/etc/fail2ban/filter.d/wordpress-freedombox.conf @@ -0,0 +1,7 @@ +[INCLUDES] +before = common.conf + +[Definition] +_daemon = apache-access +prefregex = %(__prefix_line)s +failregex = \S+ - \S+ \[[^\]]*\] "POST /wordpress/wp-login.php HTTP/\S+" 200 diff --git a/plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-auth-freedombox.conf b/plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-auth-freedombox.conf deleted file mode 100644 index 6323016c5..000000000 --- a/plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-auth-freedombox.conf +++ /dev/null @@ -1,3 +0,0 @@ -[wordpress-auth-freedombox] -enabled = true -filter = wordpress-auth-freedombox diff --git a/plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-freedombox.conf b/plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-freedombox.conf new file mode 100644 index 000000000..d68d99506 --- /dev/null +++ b/plinth/modules/wordpress/data/etc/fail2ban/jail.d/wordpress-freedombox.conf @@ -0,0 +1,4 @@ +[wordpress-freedombox] +enabled = true +filter = wordpress-freedombox +journalmatch = SYSLOG_IDENTIFIER=apache-access From 387874ecfd614769dd493d4c0a4a5aa3280508e0 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 28 Sep 2022 16:36:51 -0700 Subject: [PATCH 79/90] fail2ban: Make fail2ban log to journald - Recommendation to use 'sysout' as log target in order to log to systemd journal comes from the fail2ban.service file. Tests: - Install the changes and restart fail2ban. Notice that journalctl shows new log lines. - Logged to /var/log/fail2ban.log has stopped. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- .../security/data/etc/fail2ban/fail2ban.d/freedombox.conf | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 plinth/modules/security/data/etc/fail2ban/fail2ban.d/freedombox.conf diff --git a/plinth/modules/security/data/etc/fail2ban/fail2ban.d/freedombox.conf b/plinth/modules/security/data/etc/fail2ban/fail2ban.d/freedombox.conf new file mode 100644 index 000000000..277d4a0ad --- /dev/null +++ b/plinth/modules/security/data/etc/fail2ban/fail2ban.d/freedombox.conf @@ -0,0 +1,2 @@ +[DEFAULT] +logtarget = sysout From b7b2c9452678d27060700d7ccf6d020b663e2611 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Sat, 8 Oct 2022 04:31:04 +0000 Subject: [PATCH 80/90] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 79.0% (1179 of 1491 strings) --- plinth/locale/nb/LC_MESSAGES/django.po | 152 ++++++++++--------------- 1 file changed, 59 insertions(+), 93 deletions(-) diff --git a/plinth/locale/nb/LC_MESSAGES/django.po b/plinth/locale/nb/LC_MESSAGES/django.po index b495a320c..f32100d14 100644 --- a/plinth/locale/nb/LC_MESSAGES/django.po +++ b/plinth/locale/nb/LC_MESSAGES/django.po @@ -16,8 +16,8 @@ msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-09-14 17:19+0000\n" -"Last-Translator: ikmaak \n" +"PO-Revision-Date: 2022-10-09 07:43+0000\n" +"Last-Translator: Petter Reinholdtsen \n" "Language-Team: Norwegian Bokmål \n" "Language: nb\n" @@ -25,7 +25,7 @@ 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.1-dev\n" +"X-Generator: Weblate 4.14.1\n" #: doc/dev/_templates/layout.html:11 msgid "Page source" @@ -62,11 +62,11 @@ msgstr "Klarer ikke koble til {host}:{port}" #: plinth/forms.py:36 msgid "Backup app before uninstall" -msgstr "" +msgstr "Sikkerhetskopier program før avinstallasjon" #: plinth/forms.py:37 msgid "Restoring from the backup will restore app data." -msgstr "" +msgstr "Tilbakeføring av sikkerhetskopi vil tilbakestille programdata." #: plinth/forms.py:39 #, fuzzy @@ -2015,6 +2015,9 @@ msgid "" "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" +"Dette er en komplett eposttjenerløsning som bruker Postfix, Dovecot og " +"Rspamd. Postfix sender og mottar e-post. Dovecot gir e-postklienter tilgang " +"til din postkasse ved hjelp av IMAP og POP3. Rspamd håndterer spam." #: plinth/modules/email/__init__.py:30 msgid "" @@ -2023,6 +2026,11 @@ msgid "" "restrict outgoing email. Some lift the restriction after an explicit " "request. See manual page for more information." msgstr "" +"Eposttjeneren virker for øyeblikket ikke med mange gratis domenetjenester, " +"inkludert de som tilbys fra Freedombox-stiftelsen. Mange " +"internettleverandører begrenser også utgående epost. Noen løfter på " +"blokkeringen etter eksplisitte henvendelser. Se manualsiden for mer " +"informasjon." #: plinth/modules/email/__init__.py:35 #, python-brace-format @@ -2044,17 +2052,15 @@ msgstr "" msgid "" "During installation, any other email servers in the system will be " "uninstalled." -msgstr "" +msgstr "Enhver annen eposttjener vil bli avinstallert under installasjonen." #: plinth/modules/email/__init__.py:61 msgid "Postfix/Dovecot" msgstr "Postfix/Dovecot" #: plinth/modules/email/__init__.py:63 -#, fuzzy -#| msgid "Chat Server" msgid "Email Server" -msgstr "Nettprat-tjener" +msgstr "Eposttjener" #: plinth/modules/email/__init__.py:83 #, fuzzy @@ -2355,7 +2361,6 @@ msgstr "" "gittutorial\">Git-veiledningen." #: plinth/modules/gitweb/__init__.py:49 -#, fuzzy msgid "Read-write access to Git repositories" msgstr "Lese- og skrivetilgang til Git-kodelagre" @@ -2402,9 +2407,8 @@ msgid "Private repository" msgstr "Privat kodelager" #: plinth/modules/gitweb/forms.py:92 -#, fuzzy msgid "Allow only authorized users to access this repository." -msgstr "Tillat kun autoriserte brukere tilgang til dette kodelageret." +msgstr "Gi kun autoriserte brukere tilgang til dette kodelageret." #: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 #, fuzzy @@ -2914,11 +2918,6 @@ msgid "Anonymous Torrents" msgstr "Anonyme torrenter" #: plinth/modules/i2p/views.py:16 -#, fuzzy -#| msgid "" -#| "I2P lets you browse the Internet and hidden services (eepsites) " -#| "anonymously. For this, your browser, preferably a Tor Browser, needs to " -#| "be configured for a proxy." msgid "" "I2P lets you browse the Internet and hidden services (eepsites) anonymously. " "For this, your browser, preferably the Tor Browser, needs to be configured " @@ -3111,7 +3110,7 @@ msgstr "" #: plinth/modules/janus/__init__.py:23 msgid "A simple video conference room is included." -msgstr "" +msgstr "Et enkelt videokonferanserom er med." #: plinth/modules/janus/__init__.py:25 #, python-brace-format @@ -3124,11 +3123,11 @@ msgstr "Janus" #: plinth/modules/janus/__init__.py:43 msgid "Video Room" -msgstr "" +msgstr "Videorom" #: plinth/modules/janus/manifest.py:7 msgid "Janus Video Room" -msgstr "" +msgstr "Janus videorom" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 @@ -3557,16 +3556,12 @@ msgid "Default skin changed" msgstr "Forvalgt drakt endret" #: plinth/modules/mediawiki/views.py:102 -#, fuzzy -#| msgid "Domain name set" msgid "Domain name updated" -msgstr "Domenenavn satt" +msgstr "Domenenavn oppdatert" #: plinth/modules/mediawiki/views.py:106 -#, fuzzy -#| msgid "Domain name set" msgid "Site name updated" -msgstr "Domenenavn satt" +msgstr "Stedsnavn oppdatert" #: plinth/modules/minetest/__init__.py:35 #, fuzzy, python-brace-format @@ -3787,10 +3782,8 @@ msgid "Mumla" msgstr "Mumla" #: plinth/modules/mumble/views.py:43 -#, fuzzy -#| msgid "Password changed successfully." msgid "SuperUser password successfully updated." -msgstr "Vellykket passordbytte." +msgstr "Vellykket passordbytte for SuperUser." #: plinth/modules/mumble/views.py:48 #, fuzzy @@ -5335,10 +5328,8 @@ msgid "" msgstr "" #: plinth/modules/performance/__init__.py:41 -#, fuzzy -#| msgid "System Configuration" msgid "System Monitoring" -msgstr "Systemoppsett" +msgstr "Systemmonitorering" #: plinth/modules/power/__init__.py:14 msgid "Restart or shut down the system." @@ -5673,16 +5664,13 @@ msgid "" msgstr "" #: plinth/modules/rssbridge/__init__.py:23 -#, fuzzy, python-brace-format -#| msgid "" -#| "When enabled, Tiny Tiny RSS can be accessed by any user with a {box_name} login." +#, python-brace-format msgid "" "When enabled, RSS-Bridge can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"Tiny Tiny RSS er tilgjengelig for enhver bruker med " -"et {box_name}-brukernavn." +"Når RSS-Bridge er aktiv er den tilgjengelig for enhver bruker som er medlem av gruppen feed-reader." #: plinth/modules/rssbridge/__init__.py:27 #, python-brace-format @@ -6130,10 +6118,10 @@ msgid "" "connect to this proxy, and their data will be encrypted and proxied through " "the Shadowsocks server." msgstr "" -"Din {box_name} kan kjøre en Shadowsocks-klient, som kan koble til en " +"Din {box_name} kan kjøre en Shadowsocks-klient, som kan koble set til en " "Shadowsocks-tjener. Den vil også kjøre en SOCKS5-mellomtjener. Lokale " "enheter kan koble til denne mellomtjeneren, og deres data vil krypteres og " -"mellomtjent gjennom Shadowsocks-tjeneren." +"sendes via Shadowsocks-tjeneren." #: plinth/modules/shadowsocks/__init__.py:30 msgid "" @@ -6907,13 +6895,13 @@ msgstr "" "a>." #: plinth/modules/tor/__init__.py:34 -#, fuzzy, python-brace-format -#| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." +#, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -"En Tor SOCKS-port er tilgjengelig på din %(box_name)s på TCP port 9050." +"En Tor SOCKS-port er tilgjengelig på din {box_name} for interne nettverk på " +"TCP port 9050." #: plinth/modules/tor/__init__.py:52 msgid "Tor" @@ -7018,10 +7006,8 @@ msgstr "" "vanskeligere å sensurere denne noden. Dette hjelper andre å unngå sensur." #: plinth/modules/tor/forms.py:104 -#, fuzzy -#| msgid "Enable Tor Hidden Service" msgid "Enable Tor Hidden Service" -msgstr "Aktiver skjulte Tor-tjenester" +msgstr "Aktiver skjult Tor-tjeneste" #: plinth/modules/tor/forms.py:106 #, python-brace-format @@ -7030,9 +7016,9 @@ msgid "" "wiki or chat) without revealing its location. Do not use this for strong " "anonymity yet." msgstr "" -"En skjult tjeneste som vil tillate {box_name} å gi valgte tjenester (slike " -"som wiki eller nettprat) uten å avsløre sin beliggenhet. Ikke bruk dette for " -"å oppnå sterk anonymitet enda." +"En skjult tjeneste lar en {box_name} tilby valgte tjenester (slike som wiki " +"eller nettprat) uten å avsløre sin beliggenhet. Ikke bruk dette for å oppnå " +"sterk anonymitet enda." #: plinth/modules/tor/forms.py:111 msgid "Download software packages over Tor" @@ -7069,10 +7055,8 @@ msgid "Ports" msgstr "Porter" #: plinth/modules/tor/views.py:55 -#, fuzzy -#| msgid "An error occurred during configuration." msgid "Updating configuration" -msgstr "En feil oppsto under konfigureringen." +msgstr "Oppdaterer oppsett" #: plinth/modules/tor/views.py:72 #, fuzzy, python-brace-format @@ -7145,16 +7129,13 @@ msgstr "" "virkelig skrivebordsenhet som mulig." #: plinth/modules/ttrss/__init__.py:27 -#, fuzzy, python-brace-format -#| msgid "" -#| "When enabled, Tiny Tiny RSS can be accessed by any user with a {box_name} login." +#, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"Tiny Tiny RSS er tilgjengelig for enhver bruker med " -"et {box_name}-brukernavn." +"Når aktiv er Tiny Tiny RSS tilgjengelig for enhver " +"bruker som er medlem av gruppen feed-reader." #: plinth/modules/ttrss/__init__.py:32 #, fuzzy @@ -7197,16 +7178,12 @@ msgstr "" #: plinth/modules/upgrades/__init__.py:127 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 -#, fuzzy -#| msgid "Software Upgrades" msgid "Software Update" -msgstr "Programvare-oppgraderinger" +msgstr "Programvare-oppdatering" #: plinth/modules/upgrades/__init__.py:130 -#, fuzzy -#| msgid "FreedomBox Foundation" msgid "FreedomBox Updated" -msgstr "FreedomBox Foundation" +msgstr "FreedomBox oppdatert" #: plinth/modules/upgrades/__init__.py:222 msgid "Could not start distribution update" @@ -7308,8 +7285,7 @@ msgstr "" " " #: plinth/modules/upgrades/templates/upgrades-new-release.html:9 -#, fuzzy, python-format -#| msgid "%(box_name)s Updated" +#, python-format msgid "%(box_name)s updated" msgstr "%(box_name)s oppdatert" @@ -7450,21 +7426,19 @@ msgid "Frequent feature updates activated." msgstr "" #: plinth/modules/upgrades/views.py:223 -#, fuzzy -#| msgid "Automatic upgrades enabled" msgid "Starting distribution upgrade test." -msgstr "Automatiske oppgraderinger aktivert" +msgstr "Starter test av distribusjonsoppgradering." #: plinth/modules/users/__init__.py:29 -#, fuzzy msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" "Opprett og håndter brukerkontoer. Disse kontoene tjener som sentralisert " -"identitetsbekreftelsesmekanisme for de fleste programmer. Noen kan kreve at " -"en brukerkonto er en del av gruppen for å klarere brukrens tilgang til det." +"identitetsbekreftelsesmekanisme for de fleste programmer. Noen programmer " +"kan kreve at en brukerkonto er medlem av en gruppe for å gi brukeren tilgang " +"til programmet." #: plinth/modules/users/__init__.py:34 #, python-brace-format @@ -7505,16 +7479,14 @@ msgstr "" "Påkrevd. 150 tegn eller mindre. Kun engelske bokstaver, tall og @/./-/_." #: plinth/modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Password" msgid "Authorization Password" -msgstr "Administratorpassord" +msgstr "Tilgangspassord" #: plinth/modules/users/forms.py:84 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" +msgstr "Skriv inn passordet for bruker «{user}» for å tillate kontoendringer." #: plinth/modules/users/forms.py:93 msgid "Invalid password." @@ -7708,7 +7680,7 @@ msgstr "Bruker %(username)s opprettet." #: plinth/modules/users/views.py:76 #, python-format msgid "User %(username)s updated." -msgstr "Bruker %(username)s oppdatert." +msgstr "Oppdaterte bruker %(username)s." #: plinth/modules/users/views.py:77 msgid "Edit User" @@ -8173,7 +8145,7 @@ msgstr "Zoph" #: plinth/modules/zoph/__init__.py:57 msgid "Photo Organizer" -msgstr "Foto-organiserer" +msgstr "Organiserer fotografier" #: plinth/modules/zoph/forms.py:14 msgid "Enable OpenStreetMap for maps" @@ -8210,10 +8182,9 @@ msgid "Generic" msgstr "Generisk" #: plinth/operation.py:116 -#, fuzzy, python-brace-format -#| msgid "Error setting hostname: {exception}" +#, python-brace-format msgid "Error: {name}: {exception_message}" -msgstr "Feil ved setting av vertsnavn: {exception}" +msgstr "Feil: {name}: {exception_message}" #: plinth/operation.py:119 #, python-brace-format @@ -8270,10 +8241,8 @@ msgid "Installing app" msgstr "Installer App-er" #: plinth/setup.py:42 -#, fuzzy -#| msgid "Updating..." msgid "Updating app" -msgstr "Oppdaterer…" +msgstr "Oppdaterer program" #: plinth/setup.py:68 #, fuzzy, python-brace-format @@ -8306,10 +8275,8 @@ msgid "App installed." msgstr "Program installert." #: plinth/setup.py:87 -#, fuzzy -#| msgid "Last update" msgid "App updated" -msgstr "Siste oppdatering" +msgstr "Program oppdatert" #: plinth/setup.py:104 #, fuzzy @@ -8501,7 +8468,7 @@ msgstr "Debian:" #: plinth/templates/clients.html:114 msgid "Homebrew:" -msgstr "Hjemmelaget:" +msgstr "Homebrew:" #: plinth/templates/clients.html:117 msgid "RPM:" @@ -8562,7 +8529,7 @@ msgstr "Doner" #: plinth/templates/index.html:139 msgid "FreedomBox Foundation" -msgstr "FreedomBox Foundation" +msgstr "FreedomBox-stiftelsen" #: plinth/templates/index.html:146 msgid "Forum" @@ -8705,10 +8672,9 @@ msgid "Uninstall" msgstr "Installer" #: plinth/templates/uninstall.html:11 -#, fuzzy, python-format -#| msgid "Edit User %(username)s" +#, python-format msgid "Uninstall App %(app_name)s?" -msgstr "Rediger bruker %(username)s" +msgstr "Avinstaller program %(app_name)s?" #: plinth/templates/uninstall.html:17 msgid "Uninstalling an app is an exprimental feature." @@ -8727,7 +8693,7 @@ msgstr "Oppsett uendret" #: plinth/views.py:401 #, python-brace-format msgid "before uninstall of {app_id}" -msgstr "" +msgstr "før avinstallering av {app_id}" #: plinth/web_framework.py:114 msgid "Gujarati" From c9f924f592ecb3cb1d4493f34b659f2f25adc4cb Mon Sep 17 00:00:00 2001 From: Tymofii Lytvynenko Date: Fri, 7 Oct 2022 15:47:22 +0000 Subject: [PATCH 81/90] Translated using Weblate (Ukrainian) Currently translated at 88.0% (1313 of 1491 strings) --- plinth/locale/uk/LC_MESSAGES/django.po | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plinth/locale/uk/LC_MESSAGES/django.po b/plinth/locale/uk/LC_MESSAGES/django.po index 7d906f93e..5354268ba 100644 --- a/plinth/locale/uk/LC_MESSAGES/django.po +++ b/plinth/locale/uk/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-10-06 20:22+0000\n" +"PO-Revision-Date: 2022-10-09 07:43+0000\n" "Last-Translator: Tymofii Lytvynenko \n" "Language-Team: Ukrainian \n" @@ -3284,6 +3284,9 @@ msgid "" "server for Matrix Synapse. Disable this if you want to use a different STUN/" "TURN server." msgstr "" +"Конфігурує локальний застосунокcoturn як сервер " +"STUN/TURN для Matrix Synapse. Вимкніть цю опцію, якщо ви хочете " +"використовувати інший сервер STUN/TURN." #: plinth/modules/matrixsynapse/manifest.py:14 msgid "Element" @@ -3305,6 +3308,10 @@ msgid "" "servers will be able to reach users on this server using this domain name. " "Matrix user IDs will look like @username:domainname." msgstr "" +"Служба Matrix повинна бути налаштована для домену. Користувачі на інших " +"серверах Matrix зможуть звертатися до користувачів на цьому сервері, " +"використовуючи це доменне ім'я. Ідентифікатори користувачів Matrix матимуть " +"вигляд @ім'я_користувача:назва_домену." #: plinth/modules/matrixsynapse/templates/matrix-synapse-pre-setup.html:26 msgid "" From 99aa891454ef700a270bb53095436738d1fc5982 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Sun, 9 Oct 2022 07:32:47 +0000 Subject: [PATCH 82/90] Translated using Weblate (Albanian) Currently translated at 95.8% (1429 of 1491 strings) --- plinth/locale/sq/LC_MESSAGES/django.po | 226 ++++++++----------------- 1 file changed, 68 insertions(+), 158 deletions(-) diff --git a/plinth/locale/sq/LC_MESSAGES/django.po b/plinth/locale/sq/LC_MESSAGES/django.po index 933386cdd..e479ef644 100644 --- a/plinth/locale/sq/LC_MESSAGES/django.po +++ b/plinth/locale/sq/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-09-14 17:20+0000\n" +"PO-Revision-Date: 2022-10-09 07:43+0000\n" "Last-Translator: Besnik Bleta \n" "Language-Team: Albanian \n" @@ -17,7 +17,7 @@ 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.1-dev\n" +"X-Generator: Weblate 4.14.1\n" #: doc/dev/_templates/layout.html:11 msgid "Page source" @@ -1767,10 +1767,8 @@ msgid "Use IPv6 instead of IPv4" msgstr "Përdor IPv6, në vend se IPv4" #: plinth/modules/dynamicdns/forms.py:123 -#, fuzzy -#| msgid "secrets required" msgid "This field is required." -msgstr "lyp të fshehta" +msgstr "Kjo fushë është e domosdoshme." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 @@ -1799,50 +1797,36 @@ msgid "Last update" msgstr "Përditësimi i fundit më" #: plinth/modules/dynamicdns/templates/dynamicdns.html:21 -#, fuzzy -#| msgid "IP address" msgid "IP Address" msgstr "Adresë IP" #: plinth/modules/dynamicdns/templates/dynamicdns.html:32 -#, fuzzy -#| msgid "Access" msgid "Success" -msgstr "Hyrje" +msgstr "Sukses" #: plinth/modules/dynamicdns/templates/dynamicdns.html:36 -#, fuzzy -#| msgid "failed" msgid "Failed" -msgstr "dështoi" +msgstr "Dështoi" #: plinth/modules/dynamicdns/templates/dynamicdns.html:52 -#, fuzzy -#| msgid "No libraries available." msgid "No status available." -msgstr "S’ka biblioteka." +msgstr "S’ka gjendje të ditur." #: plinth/modules/dynamicdns/views.py:24 plinth/modules/dynamicdns/views.py:26 -#, fuzzy -#| msgid "Connection Name" msgid "Connection timed out" -msgstr "Emër Lidhjeje" +msgstr "Lidhjes i mbaroi koha" #: plinth/modules/dynamicdns/views.py:25 msgid "Could not find server" msgstr "" #: plinth/modules/dynamicdns/views.py:27 -#, fuzzy -#| msgid "Delete connection" msgid "Server refused connection" -msgstr "Fshije lidhjen" +msgstr "Shërbyesi hodhi poshtë lidhjen" #: plinth/modules/dynamicdns/views.py:28 -#, fuzzy -#| msgid "Enable auto-update" msgid "Already up-to-date" -msgstr "Aktivio vetëpërditësim" +msgstr "I përditësuar tashmë" #: plinth/modules/ejabberd/__init__.py:31 msgid "" @@ -1886,10 +1870,8 @@ msgid "Chat Server" msgstr "Shërbyes Fjalosjesh" #: plinth/modules/ejabberd/forms.py:19 -#, fuzzy -#| msgid "Domain Names" msgid "Domain names" -msgstr "Emra Përkatësish" +msgstr "Emra përkatësish" #: plinth/modules/ejabberd/forms.py:21 msgid "" @@ -2054,16 +2036,12 @@ msgid "Email Server" msgstr "Shërbyes Email-i" #: plinth/modules/email/__init__.py:83 -#, fuzzy -#| msgid "Manage Aliases" msgid "My Email Aliases" -msgstr "Administroni Aliase" +msgstr "Aliaset e Mi Email" #: plinth/modules/email/__init__.py:84 -#, fuzzy -#| msgid "Manage Aliases" msgid "Manage Aliases for Mailbox" -msgstr "Administroni Aliase" +msgstr "Administroni Aliase për Kuti postare" #: plinth/modules/email/forms.py:25 msgid "Primary domain" @@ -3438,10 +3416,6 @@ msgid "Administrator Password" msgstr "Fjalëkalim Përgjegjësi" #: plinth/modules/mediawiki/forms.py:27 -#, fuzzy -#| msgid "" -#| "Set a new password for MediaWiki's administrator account (admin). Leave " -#| "this field blank to keep the current password." msgid "" "Set a new password for MediaWiki's administrator account (admin). The " "password cannot be a common one and the minimum required length is " @@ -3449,26 +3423,23 @@ msgid "" "password." msgstr "" "Caktoni një fjalëkalim të ri për llogarinë e përgjegjësit të MediaWiki-it " -"(admin). Që të mbani fjalëkalimin e tanishëm, lëreni të zbrazët këtë fushë." +"(admin). Fjalëkalimi s’mund të jetë i rëndomtë dhe gjatësia më e pakët e " +"domosdoshme është 10 shenja. Që të mbani fjalëkalimin e " +"tanishëm, lëreni të zbrazët këtë fushë." #: plinth/modules/mediawiki/forms.py:35 -#, fuzzy -#| msgid "" -#| "Used by MediaWiki to generate URLs that point to the wiki such as in " -#| "footer, feeds and emails." msgid "" "Used by MediaWiki to generate URLs that point to the wiki such as in footer, " "feeds and emails. Examples: \"myfreedombox.example.org\" or \"example.onion" "\"." msgstr "" "E përdorur nga MediaWiki për të prodhuar URL-ra që shpien te wiki, p.sh., te " -"fundfaqja, prurjet ose email-e." +"fundfaqja, prurjet ose email-e. Shembuj: “myfreedombox.example.org”, ose " +"“example.onion”." #: plinth/modules/mediawiki/forms.py:41 -#, fuzzy -#| msgid "Kite name" msgid "Site Name" -msgstr "Emër Kite-i" +msgstr "Emër Sajti" #: plinth/modules/mediawiki/forms.py:42 msgid "Name of the site as displayed throughout the wiki." @@ -3516,12 +3487,10 @@ msgid "Password updated" msgstr "Fjalëkalimi u përditësua" #: plinth/modules/mediawiki/views.py:59 -#, fuzzy -#| msgid "Password used to encrypt data. Must match server password." msgid "Password update failed. Please choose a stronger password" msgstr "" -"Fjalëkalim i përdorur për të fshehtëzuar të dhëna. Duhet të përputhet me " -"fjalëkalimin e shërbyesit." +"Përditësimi i fjalëkalimit dështoi. Ju lutemi, zgjidhni një fjalëkalim më të " +"fortë" #: plinth/modules/mediawiki/views.py:69 msgid "Public registrations enabled" @@ -3544,16 +3513,12 @@ msgid "Default skin changed" msgstr "Lëkurçja parazgjedhje u ndryshua" #: plinth/modules/mediawiki/views.py:102 -#, fuzzy -#| msgid "Domain name set" msgid "Domain name updated" -msgstr "Emri i përkatësisë u caktua" +msgstr "Emri i përkatësisë u përditësua" #: plinth/modules/mediawiki/views.py:106 -#, fuzzy -#| msgid "Domain name set" msgid "Site name updated" -msgstr "Emri i përkatësisë u caktua" +msgstr "Emri i sajtit u përditësua" #: plinth/modules/minetest/__init__.py:35 #, python-brace-format @@ -3769,10 +3734,8 @@ msgid "SuperUser password successfully updated." msgstr "Fjalëkalimi i superpërdoruesit u përditësua me sukses." #: plinth/modules/mumble/views.py:48 -#, fuzzy -#| msgid "Password added." msgid "Join password changed" -msgstr "U shtua fjalëkalim." +msgstr "Fjalëkalimi i ardhjes u ndryshua" #: plinth/modules/mumble/views.py:53 msgid "Root channel name changed." @@ -5416,13 +5379,7 @@ msgstr "" "tjera hedhurina të papëlqyeshme Internet. " #: plinth/modules/privoxy/__init__.py:28 -#, fuzzy, python-brace-format -#| msgid "" -#| "You can use Privoxy by modifying your browser proxy settings to your " -#| "{box_name} hostname (or IP address) with port 8118. While using Privoxy, " -#| "you can see its configuration details and documentation at http://config.privoxy.org/ or http://p.p." +#, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " "{box_name} hostname (or IP address) with port 8118. Only connections from " @@ -5433,9 +5390,10 @@ msgid "" msgstr "" "Privoxy-në mund ta përdorni duke ndryshuar rregullimet e shfletuesit tuaj " "për ndërmjetës si strehëemri i {box_name}-it tuaj (ose adresa IP) me portë " -"8118. Kur përdoret Privoxy, hollësitë mbi formësimin e tij dhe dokumentim " -"për të mund të shihni te http://config." -"privoxy.org/ ose http://p.p." +"8118. Lejohen vetëm lidhje prej adresash IP rrjeti vendor. Kur përdoret " +"Privoxy, hollësitë mbi formësimin e tij dhe dokumentim për të mund të shihni " +"te http://config.privoxy.org/ ose " +"http://p.p." #: plinth/modules/privoxy/__init__.py:51 msgid "Privoxy" @@ -5668,16 +5626,13 @@ msgid "" msgstr "" #: plinth/modules/rssbridge/__init__.py:23 -#, fuzzy, python-brace-format -#| msgid "" -#| "When enabled, Tiny Tiny RSS can be accessed by any user with a {box_name} login." +#, python-brace-format msgid "" "When enabled, RSS-Bridge can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"Kur aktivizohet, Tiny Tiny RSS mund të përdoret nga cilido përdorues me kredenciale hyrjeje në {box_name}." +"Kur aktivizohet, RSS-Bridge mund të përdoret nga cilido përdorues pjesë e grupit të leximit të prurjeve." #: plinth/modules/rssbridge/__init__.py:27 #, python-brace-format @@ -6884,12 +6839,13 @@ msgstr "" "\">Shfletuesin Tor." #: plinth/modules/tor/__init__.py:34 -#, fuzzy, python-brace-format -#| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." +#, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." -msgstr "Një portë SOCKS Tor-i në %(box_name)s tuaj gjendet në portën TCP 9050." +msgstr "" +"Një portë SOCKS Tor-i për rrjete të brendshëm në {box_name} tuaj gjendet në " +"portën TCP 9050." #: plinth/modules/tor/__init__.py:52 msgid "Tor" @@ -7047,16 +7003,13 @@ msgid "Ports" msgstr "Porta" #: plinth/modules/tor/views.py:55 -#, fuzzy -#| msgid "An error occurred during configuration." msgid "Updating configuration" -msgstr "Ndodhi një gabim gjatë formësimit." +msgstr "Po përditësohet formësimi" #: plinth/modules/tor/views.py:72 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error configuring app: {error}" -msgstr "Gabim në instalimin e aplikacionit: {error}" +msgstr "Gabim në formësimin e aplikacionit: {error}" #: plinth/modules/transmission/__init__.py:23 msgid "Transmission is a BitTorrent client with a web interface." @@ -7082,16 +7035,13 @@ msgid "" msgstr "" #: plinth/modules/transmission/__init__.py:32 -#, fuzzy, python-brace-format -#| msgid "" -#| "It can be accessed by any user on {box_name} " -#| "belonging to the admin group." +#, python-brace-format msgid "" "It can be accessed by any user on {box_name} " "belonging to the bit-torrent group." msgstr "" "Mund të përdoret nga cilido përdorues në " -"{box_name} që është pjesë e grupit të përgjegjësve." +"{box_name} që është pjesë e grupit bit-torrent." #: plinth/modules/transmission/__init__.py:36 #, python-brace-format @@ -7123,16 +7073,13 @@ msgstr "" "duket si një aplikacion desktop, aq afër kësaj sa mundet." #: plinth/modules/ttrss/__init__.py:27 -#, fuzzy, python-brace-format -#| msgid "" -#| "When enabled, Tiny Tiny RSS can be accessed by any user with a {box_name} login." +#, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"Kur aktivizohet, Tiny Tiny RSS mund të përdoret nga cilido përdorues me kredenciale hyrjeje në {box_name}." +"Kur aktivizohet, Tiny Tiny RSS mund të përdoret nga cilido përdorues pjesëtar i grupit të leximit të prurjeve." #: plinth/modules/ttrss/__init__.py:32 msgid "" @@ -7368,10 +7315,8 @@ msgid "Show recent update logs" msgstr "Shfaq regjistra të freskët përditësimesh" #: plinth/modules/upgrades/templates/upgrades_configure.html:138 -#, fuzzy -#| msgid "Distribution upgrade enabled" msgid "Test Distribution Upgrade" -msgstr "Me përmirësim shpërndarjeje të aktivizuar" +msgstr "" #: plinth/modules/upgrades/templates/upgrades_configure.html:140 msgid "" @@ -7380,10 +7325,8 @@ msgid "" msgstr "" #: plinth/modules/upgrades/templates/upgrades_configure.html:150 -#, fuzzy -#| msgid "Distribution upgrade enabled" msgid "Test distribution upgrade now" -msgstr "Me përmirësim shpërndarjeje të aktivizuar" +msgstr "" #: plinth/modules/upgrades/views.py:68 #, python-brace-format @@ -7420,17 +7363,10 @@ msgid "Frequent feature updates activated." msgstr "Përditësime të shpeshta veçorish të aktivizuara." #: plinth/modules/upgrades/views.py:223 -#, fuzzy -#| msgid "Distribution upgrade enabled" msgid "Starting distribution upgrade test." -msgstr "Me përmirësim shpërndarjeje të aktivizuar" +msgstr "Po fillohet provë përmirësimi shpërndarjeje." #: plinth/modules/users/__init__.py:29 -#, fuzzy -#| msgid "" -#| "Create and managed user accounts. These accounts serve as centralized " -#| "authentication mechanism for most apps. Some apps further require a user " -#| "account to be part of a group to authorize the user to access the app." msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -8195,10 +8131,9 @@ msgid "Generic" msgstr "Elementar" #: plinth/operation.py:116 -#, fuzzy, python-brace-format -#| msgid "Error setting hostname: {exception}" +#, python-brace-format msgid "Error: {name}: {exception_message}" -msgstr "Gabim në caktim strehëemri: {exception}" +msgstr "Gabim: {name}: {exception_message}" #: plinth/operation.py:119 #, python-brace-format @@ -8222,10 +8157,8 @@ msgstr "" "Paketa {package_name} gjendet nën versionin më të ri ({latest_version})" #: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" msgid "Error running apt-get" -msgstr "Gabim Gjatë Kopjeruajtjes" +msgstr "Gabim në xhirimin e urdhrit apt-get" #: plinth/package.py:389 msgid "installing" @@ -8249,76 +8182,58 @@ msgid "Timeout waiting for package manager" msgstr "" #: plinth/setup.py:40 -#, fuzzy -#| msgid "Install Apps" msgid "Installing app" -msgstr "Instaloni Aplikacione" +msgstr "Po instalohet aplikacioni" #: plinth/setup.py:42 -#, fuzzy -#| msgid "Updating..." msgid "Updating app" -msgstr "Po përditësohet…" +msgstr "Po përditësohet aplikacioni" #: plinth/setup.py:68 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {string} {details}" +#, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Gabim në instalimin e aplikacionit: {string} {details}" #: plinth/setup.py:72 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {string} {details}" +#, python-brace-format msgid "Error updating app: {string} {details}" -msgstr "Gabim në instalimin e aplikacionit: {string} {details}" +msgstr "Gabim në përditësimin e aplikacionit: {string} {details}" #: plinth/setup.py:78 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error installing app: {error}" msgstr "Gabim në instalimin e aplikacionit: {error}" #: plinth/setup.py:81 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error updating app: {error}" -msgstr "Gabim në instalimin e aplikacionit: {error}" +msgstr "Gabim në përditësimin e aplikacionit: {error}" #: plinth/setup.py:85 -#, fuzzy -#| msgid "Application installed." msgid "App installed." msgstr "Aplikacioni u instalua." #: plinth/setup.py:87 -#, fuzzy -#| msgid "Last update" msgid "App updated" -msgstr "Përditësimi i fundit më" +msgstr "Aplikacioni u përditësua" #: plinth/setup.py:104 -#, fuzzy -#| msgid "Install Apps" msgid "Uninstalling app" -msgstr "Instaloni Aplikacione" +msgstr "Po çinstalohet aplikacion" #: plinth/setup.py:122 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {string} {details}" +#, python-brace-format msgid "Error uninstalling app: {string} {details}" -msgstr "Gabim në instalimin e aplikacionit: {string} {details}" +msgstr "Gabim në çinstalimin e aplikacionit: {string} {details}" #: plinth/setup.py:128 -#, fuzzy, python-brace-format -#| msgid "Error installing application: {error}" +#, python-brace-format msgid "Error uninstalling app: {error}" -msgstr "Gabim në instalimin e aplikacionit: {error}" +msgstr "Gabim në çinstalimin e aplikacionit: {error}" #: plinth/setup.py:131 -#, fuzzy -#| msgid "Application installed." msgid "App uninstalled." -msgstr "Aplikacioni u instalua." +msgstr "Aplikacioni u çinstalua." #: plinth/setup.py:451 msgid "Updating app packages" @@ -8625,10 +8540,8 @@ msgstr "" "%(service_name)s:" #: plinth/templates/port-forwarding-info.html:37 -#, fuzzy -#| msgid "Service Type" msgid "Service Name" -msgstr "Lloj Shërbimi" +msgstr "Emër Shërbimi" #: plinth/templates/port-forwarding-info.html:38 msgid "Protocol" @@ -8683,16 +8596,13 @@ msgstr "Përditësoje" #: plinth/templates/toolbar.html:39 plinth/templates/toolbar.html:40 #: plinth/templates/uninstall.html:36 -#, fuzzy -#| msgid "Install" msgid "Uninstall" -msgstr "Instaloje" +msgstr "Çinstaloje" #: plinth/templates/uninstall.html:11 -#, fuzzy, python-format -#| msgid "Edit User %(username)s" +#, python-format msgid "Uninstall App %(app_name)s?" -msgstr "Përpunoni Përdoruesin %(username)s" +msgstr "Të çinstalohet Aplikacioni %(app_name)s?" #: plinth/templates/uninstall.html:17 msgid "Uninstalling an app is an exprimental feature." From ecb4ce07330d936b7a5b6446bbacf35c4a03cf74 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Sun, 9 Oct 2022 08:06:59 +0000 Subject: [PATCH 83/90] Translated using Weblate (Albanian) Currently translated at 99.3% (1482 of 1491 strings) --- plinth/locale/sq/LC_MESSAGES/django.po | 134 +++++++++++++++---------- 1 file changed, 81 insertions(+), 53 deletions(-) diff --git a/plinth/locale/sq/LC_MESSAGES/django.po b/plinth/locale/sq/LC_MESSAGES/django.po index e479ef644..d294869e7 100644 --- a/plinth/locale/sq/LC_MESSAGES/django.po +++ b/plinth/locale/sq/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-10-09 07:43+0000\n" +"PO-Revision-Date: 2022-10-10 13:34+0000\n" "Last-Translator: Besnik Bleta \n" "Language-Team: Albanian \n" @@ -54,11 +54,11 @@ msgstr "S’lidhet dot me {host}:{port}" #: plinth/forms.py:36 msgid "Backup app before uninstall" -msgstr "" +msgstr "Kopjeruani aplikacionin, para se të çinstalohet" #: plinth/forms.py:37 msgid "Restoring from the backup will restore app data." -msgstr "" +msgstr "Rikthimi prej kopjeruajtjes do të rikthejë të dhëna aplikacioni." #: plinth/forms.py:39 msgid "Repository to backup to" @@ -1067,6 +1067,8 @@ msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" +"Vetëm shkronja të alfabetit të anglishtes, numra dhe shenjat _ . dhe - pa " +"hapësira apo shenja speciale. Shembull: Mediateka_ime_2000" #: plinth/modules/calibre/forms.py:30 msgid "A library with this name already exists." @@ -1291,25 +1293,27 @@ msgstr "Shfaq aplikacione dhe veçori që lypin dije më teknike." #: plinth/modules/config/forms.py:104 msgid "System-wide logging" -msgstr "" +msgstr "Regjistrim për gjithë sistemin" #: plinth/modules/config/forms.py:105 msgid "Disable logging, for privacy" -msgstr "" +msgstr "Çaktivizo regjistrim, për privatësi" #: plinth/modules/config/forms.py:107 msgid "Keep some in memory until a restart, for performance" -msgstr "" +msgstr "Mbaj ca në kujtesë, deri në një rinisje, për punim më të mirë" #: plinth/modules/config/forms.py:110 msgid "Write to disk, useful for debugging" -msgstr "" +msgstr "Shkruaje në disk, e dobishme për diagnostikim" #: plinth/modules/config/forms.py:112 msgid "" "Logs contain information about who accessed the system and debug information " "from various services" msgstr "" +"Regjistrat përmbajnë informacion se cilët kanë hyrë në sistem dhe hollësi " +"diagnostikimi nga shërbime të ndryshme" #: plinth/modules/config/views.py:50 #, python-brace-format @@ -1617,13 +1621,6 @@ msgstr "" "tuaj DNS, do të marrë një përgjigje me adresën tuaj aktuale IP." #: plinth/modules/dynamicdns/__init__.py:41 -#, fuzzy -#| msgid "" -#| "If you are looking for a free dynamic DNS account, you may find a free " -#| "GnuDIP service at ddns.freedombox.org or you may find free update URL " -#| "based services at " -#| "freedns.afraid.org." msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1631,10 +1628,10 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" "Nëse po kërkoni për një llogari falas DNS-je dinamike, mund të gjeni një " -"shërbim GnuDIP të lirë, te ddns.freedombox.org</a>, ose mund të gjeni shërbime të " -"lira me bazë përditësim URL-je, te <a href=\" target=\"_blank\"> freedns." -"afraid.org." +"shërbim GnuDIP të lirë, te ddns.freedombox.org ose mund të gjeni shërbime të lira me " +"bazë përditësim URL-je, te freedns.afraid.org." #: plinth/modules/dynamicdns/__init__.py:62 msgid "Dynamic DNS Client" @@ -1720,10 +1717,8 @@ msgid "GnuDIP" msgstr "GnuDIP" #: plinth/modules/dynamicdns/forms.py:57 -#, fuzzy -#| msgid "other update URL" msgid "Other update URL" -msgstr "tjetër URL përditësimesh" +msgstr "Tjetër URL përditësimesh" #: plinth/modules/dynamicdns/forms.py:59 msgid "Service Type" @@ -1818,7 +1813,7 @@ msgstr "Lidhjes i mbaroi koha" #: plinth/modules/dynamicdns/views.py:25 msgid "Could not find server" -msgstr "" +msgstr "S’u gjet dot shërbyes" #: plinth/modules/dynamicdns/views.py:27 msgid "Server refused connection" @@ -1878,6 +1873,9 @@ msgid "" "Domains to be used by ejabberd. Note that user accounts are unique for each " "domain, and migrating users to a new domain name is not yet implemented." msgstr "" +"Përkatësi për t’u përdorur nga ejabberd. Kini parasysh se llogaritë e " +"përdoruesve janë unike për çdo përkatësi dhe migrimi i përdoruesve te një " +"emër i ri përkatësie s’është sendërtuar ende." #: plinth/modules/ejabberd/forms.py:26 msgid "Enable Message Archive Management" @@ -1993,6 +1991,10 @@ msgid "" "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" +"Kjo është një zgjidhje e plotë shërbyes email që përdor Postfix, Dovecot dhe " +"Rspamd. Postfix-i dërgon dhe merr email-e. Dovecot u lejon klientëve email " +"të përdorin kutinë tuaj postare përmes IMAP apo POP3. Rspamd trajton " +"mesazhet e padëshiruar." #: plinth/modules/email/__init__.py:30 msgid "" @@ -2001,6 +2003,11 @@ msgid "" "restrict outgoing email. Some lift the restriction after an explicit " "request. See manual page for more information." msgstr "" +"Shërbyesi email aktualisht nuk funksionon me mjaft shërbime të lira " +"përkatësish, përfshi ato të FreedomBox Foundation. Gjithashtu mjaft ISP " +"kufizojnë email-t e dërguar. Disa prej tyre e heqin kufizimin pas një " +"kërkese shprehimisht për këtë. Për më tepër hollësi, shihni faqen e " +"doracakut." #: plinth/modules/email/__init__.py:35 #, python-brace-format @@ -2011,6 +2018,11 @@ msgid "" "Necessary aliases such as \"postmaster\" are automatically created pointing " "to the first admin user." msgstr "" +"Çdo përdorues në {box_name} merr një adresë email të ngjashme me përdorues@" +"përkatësiaime.shembull. Do të marrë gjithashtu email nga krejt adresat që " +"duken si përdorues+foo@përkatësiaime.shembull. Më tej, mund të shtojë aliase " +"te adresa e tij email. Aliase të nevojshëm, të tillë si “postmaster” " +"krijohen automatikisht dhe shpien te i pari përdorues përgjegjës." #: plinth/modules/email/__init__.py:41 msgid "" @@ -2115,7 +2127,7 @@ msgstr "Administroni Të Padëshiruarat" #: plinth/modules/email/templates/email.html:22 msgid "DNS Records" -msgstr "" +msgstr "Zëra DNS" #: plinth/modules/email/templates/email.html:25 msgid "" @@ -2125,19 +2137,19 @@ msgstr "" #: plinth/modules/email/templates/email.html:36 msgid "TTL" -msgstr "" +msgstr "TTL" #: plinth/modules/email/templates/email.html:37 msgid "Class" -msgstr "" +msgstr "Klasë" #: plinth/modules/email/templates/email.html:39 msgid "Priority" -msgstr "" +msgstr "Përparësi" #: plinth/modules/email/templates/email.html:40 msgid "Weight" -msgstr "" +msgstr "Madhësi" #: plinth/modules/email/templates/email.html:41 #: plinth/modules/minetest/templates/minetest.html:18 @@ -2146,7 +2158,7 @@ msgstr "Portë" #: plinth/modules/email/templates/email.html:42 msgid "Host/Target/Value" -msgstr "" +msgstr "Strehë/Objektiv/Vlerë" #: plinth/modules/firewall/__init__.py:26 #, python-brace-format @@ -2612,38 +2624,40 @@ msgstr "Mësoni më tepër…" #: plinth/modules/help/templates/help_contribute.html:46 msgid "How can I help?" -msgstr "" +msgstr "Si mund t’ju ndihmoj?" #: plinth/modules/help/templates/help_contribute.html:48 msgid "" "Below is a list of opportunities for contributing to Debian. It has been " "filtered to only show packages that are installed on this system." msgstr "" +"Më poshtë gjendet një listë mundësish për të dhënë ndihmesë te Debian. Është " +"filtruar për të shfaqur vetëm paketa që janë të instaluara në këtë sistem." #: plinth/modules/help/templates/help_contribute.html:59 msgid "Show issues" -msgstr "" +msgstr "Shfaq çështje" #: plinth/modules/help/templates/help_contribute.html:63 msgid "Packages that will be removed from Debian testing" -msgstr "" +msgstr "Paketa që do të hiqen nga dega Debian testing" #: plinth/modules/help/templates/help_contribute.html:69 #: plinth/modules/help/templates/help_contribute.html:85 msgid "source package:" -msgstr "" +msgstr "paketë burim:" #: plinth/modules/help/templates/help_contribute.html:80 msgid "Packages that are not in Debian testing" -msgstr "" +msgstr "Paketa që s’janë pjesë e degës Debian testing" #: plinth/modules/help/templates/help_contribute.html:92 msgid "Good first issues for beginners" -msgstr "" +msgstr "Çështje të përshtatshme për fillestarë" #: plinth/modules/help/templates/help_contribute.html:104 msgid "Issues for which the package maintainer has requested help" -msgstr "" +msgstr "Çështje për të cilat mirëmbajtësi i paketës ka kërkuar ndihmë" #: plinth/modules/help/templates/help_feedback.html:12 #, python-format @@ -3049,16 +3063,18 @@ msgstr "" #: plinth/modules/janus/__init__.py:22 msgid "Janus is a lightweight WebRTC server." -msgstr "" +msgstr "Janus është një shërbyes WebRTC i peshës së lehtë." #: plinth/modules/janus/__init__.py:23 msgid "A simple video conference room is included." -msgstr "" +msgstr "Përfshihet një dhomë e thjeshtë konferencash me video." #: plinth/modules/janus/__init__.py:25 #, python-brace-format msgid "Coturn is required to use Janus." msgstr "" +"Coturn është i domosdoshëm për të përdorur " +"Janus-in." #: plinth/modules/janus/__init__.py:41 msgid "Janus" @@ -3066,11 +3082,11 @@ msgstr "Janus" #: plinth/modules/janus/__init__.py:43 msgid "Video Room" -msgstr "" +msgstr "Dhomë Me Video" #: plinth/modules/janus/manifest.py:7 msgid "Janus Video Room" -msgstr "" +msgstr "Janus Video Room" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 @@ -3443,7 +3459,7 @@ msgstr "Emër Sajti" #: plinth/modules/mediawiki/forms.py:42 msgid "Name of the site as displayed throughout the wiki." -msgstr "" +msgstr "Emër i sajtit siç shfaqet nëpër wiki." #: plinth/modules/mediawiki/forms.py:46 msgid "Enable public registrations" @@ -3703,17 +3719,19 @@ msgstr "" #: plinth/modules/mumble/forms.py:40 msgid "Set a password to join the server" -msgstr "" +msgstr "Që të bëheni pjesë e një shërbyesi, caktoni një fjalëkalim" #: plinth/modules/mumble/forms.py:42 msgid "" "Set a password that is required to join the server. Leave empty to use the " "current password." msgstr "" +"Caktoni një fjalëkalim që është i domosdoshëm për të hyrë te shërbyesi. Për " +"të përdorur fjalëkalimin e tanishëm, lëreni të zbrazët." #: plinth/modules/mumble/forms.py:48 msgid "Set the name for the root channel" -msgstr "" +msgstr "Caktoni emrin e kanalit rrënjë" #: plinth/modules/mumble/forms.py:52 msgid "" @@ -3739,7 +3757,7 @@ msgstr "Fjalëkalimi i ardhjes u ndryshua" #: plinth/modules/mumble/views.py:53 msgid "Root channel name changed." -msgstr "" +msgstr "Emri i kanalit rrënjë ndryshoi" #: plinth/modules/names/__init__.py:22 #, python-brace-format @@ -5641,6 +5659,9 @@ msgid "" "follow various websites. When adding a feed, enable authentication and use " "your {box_name} credentials." msgstr "" +"RSS-Bridge-in mund ta përdorni me Tiny Tiny RSS " +"për të ndjekur sajte të ndryshëm. Kur shtohet një prurje, aktivizoni " +"mirëfilltësimin dhe përdorni kredencialet tuaj për {box_name}." #: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 msgid "Read and subscribe to news feeds" @@ -5649,11 +5670,11 @@ msgstr "Lexoni dhe pajtohuni te prurje lajmesh" #: plinth/modules/rssbridge/__init__.py:48 #: plinth/modules/rssbridge/manifest.py:10 msgid "RSS-Bridge" -msgstr "" +msgstr "RSS-Bridge" #: plinth/modules/rssbridge/__init__.py:49 msgid "RSS Feed Generator" -msgstr "" +msgstr "Prodhues Prurjesh RSS" #: plinth/modules/samba/__init__.py:27 msgid "" @@ -7056,6 +7077,8 @@ msgid "" "After a download has completed, you can also access your files using the Sharing app." msgstr "" +"Pasi të jetë plotësuar një shkarkim, te kartelat tuaja mund të hyni edhe " +"duke përdorur aplikacionin Ndarje Me të Tjerë." #: plinth/modules/transmission/__init__.py:66 #: plinth/modules/transmission/manifest.py:6 @@ -7323,6 +7346,9 @@ msgid "" "This will attempt to upgrade the system from stable to testing. It " "is meant only for development use." msgstr "" +"Kjo do të rreket të përmirësojë sistemin nga versioni i qëndrueshëm në " +"versionin testim. Është menduar vetëm për përdorim zhvillimi të " +"platformës." #: plinth/modules/upgrades/templates/upgrades_configure.html:150 msgid "Test distribution upgrade now" @@ -8138,17 +8164,17 @@ msgstr "Gabim: {name}: {exception_message}" #: plinth/operation.py:119 #, python-brace-format msgid "Waiting to start: {name}" -msgstr "" +msgstr "Po pritet të fillohet: {name}" #: plinth/operation.py:125 #, python-brace-format msgid "Finished: {name}" -msgstr "" +msgstr "Përfundoi: {name}" #: plinth/package.py:191 #, python-brace-format msgid "Package {expression} is not available for install" -msgstr "" +msgstr "Paketa {expression} s’është e gatshme për instalim" #: plinth/package.py:204 #, python-brace-format @@ -8179,7 +8205,7 @@ msgstr "kartelë formësimi: {file}" #: plinth/package.py:423 plinth/package.py:448 msgid "Timeout waiting for package manager" -msgstr "" +msgstr "Mbaroi koha teksa pritej për përgjegjës paketash" #: plinth/setup.py:40 msgid "Installing app" @@ -8237,7 +8263,7 @@ msgstr "Aplikacioni u çinstalua." #: plinth/setup.py:451 msgid "Updating app packages" -msgstr "" +msgstr "Po përditësohet paketa aplikacioni" #: plinth/templates/403.html:10 msgid "403 Forbidden" @@ -8463,7 +8489,7 @@ msgstr "FreedomBox Foundation" #: plinth/templates/index.html:146 msgid "Forum" -msgstr "" +msgstr "Forum" #: plinth/templates/index.html:151 msgid "IRC Chatroom" @@ -8606,13 +8632,15 @@ msgstr "Të çinstalohet Aplikacioni %(app_name)s?" #: plinth/templates/uninstall.html:17 msgid "Uninstalling an app is an exprimental feature." -msgstr "" +msgstr "Çinstalimi i një aplikacioni është një veçori eksperimentale." #: plinth/templates/uninstall.html:23 msgid "" "All app data and configuration will be permanently lost. App may be " "installed freshly again." msgstr "" +"Krejt të dhënat dhe formësimi i aplikacionit do të humbin përgjithnjë. " +"Aplikacioni mund të instalohet sërish nga e para." #: plinth/views.py:221 msgid "Setting unchanged" @@ -8621,7 +8649,7 @@ msgstr "Rregullim i pandryshuar" #: plinth/views.py:401 #, python-brace-format msgid "before uninstall of {app_id}" -msgstr "" +msgstr "para çinstalimit të {app_id}" #: plinth/web_framework.py:114 msgid "Gujarati" From 95f2d372d8e47844d9f21e34d6dafe804dc19ef3 Mon Sep 17 00:00:00 2001 From: nbenedek Date: Sat, 24 Sep 2022 17:43:22 +0200 Subject: [PATCH 84/90] matrix: Add fail2ban jail Test: - Setup Matrix on a VPS with a FQDN and a valid LE certificate, then add these configs to fail2ban. - On a production server apply the changes of MR !2296 - Setup the fail2ban filter and jail, then restart fail2ban - Trying to log in unsuccessfully from FluffyChat leads to a 10 min ban Result: `sudo fail2ban-client status matrix-synapse-auth-freedombox` returns the following output, but the server actually remains accessible in every way. ``` Status for the jail: matrix-synapse-auth-freedombox |- Filter | |- Currently failed: 1 | |- Total failed: 11 | `- Journal matches: `- Actions |- Currently banned: 1 |- Total banned: 1 `- Banned IP list: MY IP ``` Signed-off-by: nbenedek --- .../data/etc/fail2ban/filter.d/matrix-auth-freedombox.conf | 7 +++++++ .../data/etc/fail2ban/jail.d/matrix-auth-freedombox.conf | 4 ++++ 2 files changed, 11 insertions(+) create mode 100644 plinth/modules/matrixsynapse/data/etc/fail2ban/filter.d/matrix-auth-freedombox.conf create mode 100644 plinth/modules/matrixsynapse/data/etc/fail2ban/jail.d/matrix-auth-freedombox.conf diff --git a/plinth/modules/matrixsynapse/data/etc/fail2ban/filter.d/matrix-auth-freedombox.conf b/plinth/modules/matrixsynapse/data/etc/fail2ban/filter.d/matrix-auth-freedombox.conf new file mode 100644 index 000000000..498135e3d --- /dev/null +++ b/plinth/modules/matrixsynapse/data/etc/fail2ban/filter.d/matrix-auth-freedombox.conf @@ -0,0 +1,7 @@ +[INCLUDES] +before = common.conf + +[Definition] +_daemon = apache-access +prefregex = %(__prefix_line)s +failregex = \S+ - \S+ \[[^\]]*\] "POST /_matrix/client/.*/login HTTP/\S+" 403 diff --git a/plinth/modules/matrixsynapse/data/etc/fail2ban/jail.d/matrix-auth-freedombox.conf b/plinth/modules/matrixsynapse/data/etc/fail2ban/jail.d/matrix-auth-freedombox.conf new file mode 100644 index 000000000..3fb52a559 --- /dev/null +++ b/plinth/modules/matrixsynapse/data/etc/fail2ban/jail.d/matrix-auth-freedombox.conf @@ -0,0 +1,4 @@ +[matrix-auth-freedombox] +enabled = true +port = http,https +journalmatch = SYSLOG_IDENTIFIER=apache-access From 5dd2751514ae354ff26e38dc8796b6989b062db1 Mon Sep 17 00:00:00 2001 From: Nikita Epifanov Date: Mon, 10 Oct 2022 16:57:12 +0000 Subject: [PATCH 85/90] Translated using Weblate (Russian) Currently translated at 96.7% (1443 of 1491 strings) --- plinth/locale/ru/LC_MESSAGES/django.po | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/plinth/locale/ru/LC_MESSAGES/django.po b/plinth/locale/ru/LC_MESSAGES/django.po index 7a01812e5..b39a27ed7 100644 --- a/plinth/locale/ru/LC_MESSAGES/django.po +++ b/plinth/locale/ru/LC_MESSAGES/django.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-09-26 19:51-0400\n" -"PO-Revision-Date: 2022-09-14 17:19+0000\n" -"Last-Translator: ikmaak \n" +"PO-Revision-Date: 2022-10-10 18:05+0000\n" +"Last-Translator: Nikita Epifanov \n" "Language-Team: Russian \n" "Language: ru\n" @@ -18,7 +18,7 @@ msgstr "" "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 4.14.1-dev\n" +"X-Generator: Weblate 4.14.1\n" #: doc/dev/_templates/layout.html:11 msgid "Page source" @@ -55,17 +55,15 @@ msgstr "Невозможно подключиться к {host}:{port}" #: plinth/forms.py:36 msgid "Backup app before uninstall" -msgstr "" +msgstr "Сделать резервное копирование приложения перед удалением" #: plinth/forms.py:37 msgid "Restoring from the backup will restore app data." -msgstr "" +msgstr "Восстановление из резервной копии восстановит данные приложения." #: plinth/forms.py:39 -#, fuzzy -#| msgid "Repository not found" msgid "Repository to backup to" -msgstr "Репозиторий не найден" +msgstr "Репозиторий для резервного копирования" #: plinth/forms.py:56 msgid "Select a domain name to be used with this application" @@ -1297,11 +1295,11 @@ msgstr "" #, fuzzy #| msgid "System Monitoring" msgid "System-wide logging" -msgstr "Системный мониторинг" +msgstr "Общесистемное ведение журнала" #: plinth/modules/config/forms.py:105 msgid "Disable logging, for privacy" -msgstr "" +msgstr "Отключить ведение журнала для обеспечения конфиденциальности" #: plinth/modules/config/forms.py:107 msgid "Keep some in memory until a restart, for performance" From 7e2ebcb7437ebcaf1f883e2d4679f3916b69fe87 Mon Sep 17 00:00:00 2001 From: nbenedek Date: Sat, 17 Sep 2022 10:30:48 +0200 Subject: [PATCH 86/90] privacy: Add new system app for popularity-contest - Keep the description about app generic - Remove enable/disable option - Create a booleanfield to turn on/off popcon - Don't re-enable popcon during an update Tests: - When enabling/disabling the option, the `"PARTICIPATE"` value in `/etc/popularity-contest.conf` is changed to yes/no as expected. For reference see `/var/lib/dpkg/info/popularity-contest.templates` - When popcon option is enabled, running sudo sh -x /etc/cron.daily/popularity-context shows that execution was successful and data was submitted. Remove files /var/log/popularity-contest* and /var/lib/popularity-contest/lastsub if necessary. Gpg is used and encrypted data is what was submitted. - When popcon option is disabled, running sudo sh -x /etc/cron.daily/popularity-context shows that execution stopped because the option is disabled. Signed-off-by: nbenedek [sunil: Add a notification to tell users about privacy app] [sunil: Correct the URL to /sys] [sunil: Minor code styling changes and updates to description, icon] [sunil: Ensure that popcon works with encryption] [sunil: Write configuration to a separate file] [sunil: Use Shellvars lens instead of Php lns] [sunil: Add functional tests] [sunil: Backup/restore the configuration file] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/privacy/__init__.py | 79 +++++++++++++++++++ .../data/etc/plinth/modules-enabled/privacy | 1 + plinth/modules/privacy/forms.py | 24 ++++++ plinth/modules/privacy/manifest.py | 6 ++ plinth/modules/privacy/privileged.py | 51 ++++++++++++ plinth/modules/privacy/tests/__init__.py | 0 .../modules/privacy/tests/test_functional.py | 59 ++++++++++++++ plinth/modules/privacy/urls.py | 10 +++ plinth/modules/privacy/views.py | 38 +++++++++ plinth/tests/functional/__init__.py | 4 +- pyproject.toml | 1 + 11 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 plinth/modules/privacy/__init__.py create mode 100644 plinth/modules/privacy/data/etc/plinth/modules-enabled/privacy create mode 100644 plinth/modules/privacy/forms.py create mode 100644 plinth/modules/privacy/manifest.py create mode 100644 plinth/modules/privacy/privileged.py create mode 100644 plinth/modules/privacy/tests/__init__.py create mode 100644 plinth/modules/privacy/tests/test_functional.py create mode 100644 plinth/modules/privacy/urls.py create mode 100644 plinth/modules/privacy/views.py diff --git a/plinth/modules/privacy/__init__.py b/plinth/modules/privacy/__init__.py new file mode 100644 index 000000000..e0bdfacd8 --- /dev/null +++ b/plinth/modules/privacy/__init__.py @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""FreedomBox app to the Privacy app.""" + +import augeas +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext_noop + +from plinth import app as app_module +from plinth import menu +from plinth.modules.backups.components import BackupRestore +from plinth.package import Packages + +from . import manifest, privileged + +_description = [_('Manage system-wide privacy settings.')] + + +class PrivacyApp(app_module.App): + """FreedomBox app for Privacy.""" + + app_id = 'privacy' + + _version = 1 + + can_be_disabled = False + + def __init__(self): + """Create components for the app.""" + super().__init__() + + info = app_module.Info(app_id=self.app_id, version=self._version, + is_essential=True, name=_('Privacy'), + icon='fa-eye-slash', description=_description, + manual_page=None) + self.add(info) + + menu_item = menu.Menu('menu-privacy', info.name, + info.short_description, info.icon, + 'privacy:index', parent_url_name='system') + self.add(menu_item) + + packages = Packages('packages-privacy', ['popularity-contest', 'gpg']) + self.add(packages) + + backup_restore = BackupRestore('backup-restore-privacy', + **manifest.backup) + self.add(backup_restore) + + def setup(self, old_version): + """Install and configure the app.""" + super().setup(old_version) + privileged.setup() + if old_version == 0: + privileged.set_configuration(enable_popcon=True) + _show_privacy_notification() + + +def _show_privacy_notification(): + """Show a notification asking user to review privacy settings.""" + from plinth.notification import Notification + message = gettext_noop( + 'Please update privacy settings to match your preferences.') + data = { + 'app_name': 'translate:' + gettext_noop('Privacy'), + 'app_icon': 'fa-eye-slash' + } + title = gettext_noop('Review privacy setting') + actions_ = [{ + 'type': 'link', + 'class': 'primary', + 'text': gettext_noop('Go to {app_name}'), + 'url': 'privacy:index' + }, { + 'type': 'dismiss' + }] + Notification.update_or_create(id='privacy-review', app_id='privacy', + severity='info', title=title, + message=message, actions=actions_, data=data, + group='admin') diff --git a/plinth/modules/privacy/data/etc/plinth/modules-enabled/privacy b/plinth/modules/privacy/data/etc/plinth/modules-enabled/privacy new file mode 100644 index 000000000..a782d038c --- /dev/null +++ b/plinth/modules/privacy/data/etc/plinth/modules-enabled/privacy @@ -0,0 +1 @@ +plinth.modules.privacy diff --git a/plinth/modules/privacy/forms.py b/plinth/modules/privacy/forms.py new file mode 100644 index 000000000..c824b63a5 --- /dev/null +++ b/plinth/modules/privacy/forms.py @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""FreedomBox privacy app.""" + +from django import forms +from django.utils.translation import gettext_lazy as _ + +from plinth import cfg +from plinth.utils import format_lazy + + +class PrivacyForm(forms.Form): + """Privacy configuration form.""" + + enable_popcon = forms.BooleanField( + label=_('Periodically submit a list of apps used (suggested)'), + required=False, help_text=format_lazy( + _('Help Debian/{box_name} developers by participating in the ' + 'Popularity Contest package survey program. When enabled, a ' + 'list of apps used on this system will be anonymously submitted ' + 'to Debian every week. Statistics for the data collected are ' + 'publicly available at popcon.debian.org. Submission happens over ' + 'the Tor network for additional anonymity if Tor app is enabled.' + ), box_name=_(cfg.box_name))) diff --git a/plinth/modules/privacy/manifest.py b/plinth/modules/privacy/manifest.py new file mode 100644 index 000000000..a10591d1c --- /dev/null +++ b/plinth/modules/privacy/manifest.py @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Application manifest for privacy app.""" + +from . import privileged + +backup = {'config': {'files': [str(privileged.CONFIG_FILE)]}} diff --git a/plinth/modules/privacy/privileged.py b/plinth/modules/privacy/privileged.py new file mode 100644 index 000000000..e5a790276 --- /dev/null +++ b/plinth/modules/privacy/privileged.py @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Configure Privacy App.""" + +import pathlib +from typing import Optional + +import augeas + +from plinth.actions import privileged + +CONFIG_FILE = pathlib.Path('/etc/popularity-contest.d/freedombox.conf') + + +@privileged +def setup(): + """Create initial popcon configuration.""" + CONFIG_FILE.parent.mkdir(exist_ok=True) + CONFIG_FILE.touch() + + aug = _load_augeas() + aug.set('ENCRYPT', 'yes') + aug.save() + + +@privileged +def set_configuration(enable_popcon: Optional[bool] = None): + """Update popcon configuration.""" + aug = _load_augeas() + if enable_popcon: + aug.set('PARTICIPATE', 'yes') + else: + aug.set('PARTICIPATE', 'no') + + aug.save() + + +def get_configuration() -> dict[str, bool]: + """Return if popcon participation is enabled.""" + aug = _load_augeas() + value = aug.get('PARTICIPATE') + return {'enable_popcon': (value == 'yes')} + + +def _load_augeas(): + """Initialize Augeas.""" + aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + + augeas.Augeas.NO_MODL_AUTOLOAD) + aug.transform('Shellvars', str(CONFIG_FILE)) + aug.set('/augeas/context', '/files' + str(CONFIG_FILE)) + aug.load() + return aug diff --git a/plinth/modules/privacy/tests/__init__.py b/plinth/modules/privacy/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plinth/modules/privacy/tests/test_functional.py b/plinth/modules/privacy/tests/test_functional.py new file mode 100644 index 000000000..21b0ee1f4 --- /dev/null +++ b/plinth/modules/privacy/tests/test_functional.py @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Functional, browser based tests for privacy app.""" + +import pytest + +from plinth.tests import functional + +pytestmark = [pytest.mark.system, pytest.mark.privacy] + + +class TestPrivacyApp(functional.BaseAppTests): + """Tests for privacy app.""" + + app_name = 'privacy' + has_service = False + has_web = False + disable_after_tests = False + + @pytest.fixture(autouse=True) + def fixture_background(self, session_browser): + """Login, install, and enable the app.""" + functional.login(session_browser) + functional.nav_to_module(session_browser, self.app_name) + yield + + def test_enable_disable(self, session_browser): + """Skip test for enabling and disabling the app.""" + pytest.skip('Can not be disabled') + + @pytest.mark.backups + def test_enable_disable_popcon(self, session_browser): + """Test that popcon can be enable/disabled.""" + functional.change_checkbox_status(session_browser, self.app_name, + 'id_enable_popcon', 'disabled') + functional.change_checkbox_status(session_browser, self.app_name, + 'id_enable_popcon', 'enabled') + assert session_browser.find_by_id('id_enable_popcon').checked + functional.change_checkbox_status(session_browser, self.app_name, + 'id_enable_popcon', 'disabled') + assert not session_browser.find_by_id('id_enable_popcon').checked + + @pytest.mark.backups + def test_backup_restore(self, session_browser): + """Test that backup and restore operations work on the app.""" + functional.change_checkbox_status(session_browser, self.app_name, + 'id_enable_popcon', 'disabled') + functional.backup_create(session_browser, self.app_name, + 'test_' + self.app_name) + functional.nav_to_module(session_browser, self.app_name) + functional.change_checkbox_status(session_browser, self.app_name, + 'id_enable_popcon', 'enabled') + functional.backup_restore(session_browser, self.app_name, + 'test_' + self.app_name) + functional.nav_to_module(session_browser, self.app_name) + assert not session_browser.find_by_id('id_enable_popcon').checked + + def test_uninstall(self, session_browser): + """Skip test for uninstall.""" + pytest.skip('Essential app') diff --git a/plinth/modules/privacy/urls.py b/plinth/modules/privacy/urls.py new file mode 100644 index 000000000..d0c28ee5c --- /dev/null +++ b/plinth/modules/privacy/urls.py @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""URLs for the Privacy module.""" + +from django.urls import re_path + +from .views import PrivacyAppView + +urlpatterns = [ + re_path(r'^sys/privacy/$', PrivacyAppView.as_view(), name='index'), +] diff --git a/plinth/modules/privacy/views.py b/plinth/modules/privacy/views.py new file mode 100644 index 000000000..a60e091e1 --- /dev/null +++ b/plinth/modules/privacy/views.py @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Views for privacy app.""" + +from django.contrib import messages +from django.utils.translation import gettext as _ + +from plinth.modules.privacy.forms import PrivacyForm +from plinth.views import AppView + +from . import privileged + + +class PrivacyAppView(AppView): + """Serve configuration page.""" + + app_id = 'privacy' + form_class = PrivacyForm + + def get_initial(self): + """Return the values to fill in the form.""" + initial = super().get_initial() + initial.update(privileged.get_configuration()) + return initial + + def form_valid(self, form): + """Change the configurations of Minetest service.""" + new_config = form.cleaned_data + old_config = form.initial + + changes = {} + if old_config['enable_popcon'] != new_config['enable_popcon']: + changes['enable_popcon'] = new_config['enable_popcon'] + + if changes: + privileged.set_configuration(**changes) + messages.success(self.request, _('Configuration updated')) + + return super().form_valid(form) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index 1af83bc06..508c4980d 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -50,8 +50,8 @@ _site_url = { _sys_modules = [ 'avahi', 'backups', 'bind', 'cockpit', 'config', 'datetime', 'diagnostics', 'dynamicdns', 'firewall', 'letsencrypt', 'names', 'networks', 'pagekite', - 'performance', 'power', 'security', 'snapshot', 'ssh', 'storage', - 'upgrades', 'users' + 'performance', 'power', 'privacy', 'security', 'snapshot', 'ssh', + 'storage', 'upgrades', 'users' ] diff --git a/pyproject.toml b/pyproject.toml index 5ef7e8f2f..0af5e8616 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ markers = [ "openvpn", "pagekite", "performance", + "privacy", "privoxy", "quassel", "radicale", From 236ad3771af40b6deb772c84e9dc8c1aa645356d Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 10 Oct 2022 17:57:32 -0700 Subject: [PATCH 87/90] privacy: Set vendor as FreedomBox for dpkg and popularity-contest - This changes sets the default dpkg vendor as FreedomBox. 'Debian' is still the parent of the vendor. - This results in popcon setting the Vendor as FreedomBox. This allows measuring the popular of FreedomBox distribution itself as against other Debian derivatives in the section 'Statistics per distributions reporting to Debian' of https://popcon.debian.org Tests: - Run `sudo ./setup.py install` and freedombox service. Privacy app will be setup for the first time. In /etc/dpkg/origins/ the file default is a symlink pointing to /etc/dpkg/origins/fredombox. Running 'sudo sh +x /etc/cron.daily/popularity' runs successfully. Remove files /var/lib/popularity-contest/lastsub /var/log/popularity-contest* if necessary. The file /etc/log/popularity-contest shows VENDOR:FreedomBox in the first line. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/privacy/data/etc/dpkg/origins/freedombox | 4 ++++ plinth/modules/privacy/privileged.py | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 plinth/modules/privacy/data/etc/dpkg/origins/freedombox diff --git a/plinth/modules/privacy/data/etc/dpkg/origins/freedombox b/plinth/modules/privacy/data/etc/dpkg/origins/freedombox new file mode 100644 index 000000000..9f2810477 --- /dev/null +++ b/plinth/modules/privacy/data/etc/dpkg/origins/freedombox @@ -0,0 +1,4 @@ +Vendor: FreedomBox +Vendor-URL: https://freedombox.org/ +Bugs: https://salsa.debian.org/freedombox-team/freedombox/-/issues/new +Parent: Debian diff --git a/plinth/modules/privacy/privileged.py b/plinth/modules/privacy/privileged.py index e5a790276..04faff907 100644 --- a/plinth/modules/privacy/privileged.py +++ b/plinth/modules/privacy/privileged.py @@ -21,6 +21,13 @@ def setup(): aug.set('ENCRYPT', 'yes') aug.save() + # Set the vendor to 'FreedomBox' with 'Debian' as parent + default_link = pathlib.Path('/etc/dpkg/origins/default') + debian_link = pathlib.Path('/etc/dpkg/origins/debian') + if default_link.is_symlink() and default_link.resolve() == debian_link: + default_link.unlink() + default_link.symlink_to('freedombox') + @privileged def set_configuration(enable_popcon: Optional[bool] = None): From ae999c3ff079371ee7e879bc408b6216a9d25f71 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Mon, 10 Oct 2022 21:35:37 -0400 Subject: [PATCH 88/90] locale: Update translation strings Signed-off-by: James Valleroy --- plinth/locale/ar/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/ar_SA/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/bg/LC_MESSAGES/django.po | 1133 +++++++++-------- plinth/locale/bn/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/cs/LC_MESSAGES/django.po | 1214 +++++++++--------- plinth/locale/da/LC_MESSAGES/django.po | 1157 +++++++++-------- plinth/locale/de/LC_MESSAGES/django.po | 1213 +++++++++--------- plinth/locale/django.pot | 1110 ++++++++--------- plinth/locale/el/LC_MESSAGES/django.po | 1173 +++++++++--------- plinth/locale/es/LC_MESSAGES/django.po | 1213 +++++++++--------- plinth/locale/fa/LC_MESSAGES/django.po | 1147 +++++++++-------- plinth/locale/fake/LC_MESSAGES/django.po | 1158 +++++++++-------- plinth/locale/fr/LC_MESSAGES/django.po | 1221 +++++++++--------- plinth/locale/gl/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/gu/LC_MESSAGES/django.po | 1132 +++++++++-------- plinth/locale/hi/LC_MESSAGES/django.po | 1155 +++++++++-------- plinth/locale/hu/LC_MESSAGES/django.po | 1214 +++++++++--------- plinth/locale/id/LC_MESSAGES/django.po | 1151 ++++++++--------- plinth/locale/it/LC_MESSAGES/django.po | 1153 +++++++++-------- plinth/locale/ja/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/kn/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/lt/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/lv/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/nb/LC_MESSAGES/django.po | 1171 +++++++++--------- plinth/locale/nl/LC_MESSAGES/django.po | 1209 +++++++++--------- plinth/locale/pl/LC_MESSAGES/django.po | 1153 +++++++++-------- plinth/locale/pt/LC_MESSAGES/django.po | 1123 +++++++++-------- plinth/locale/ru/LC_MESSAGES/django.po | 1215 +++++++++--------- plinth/locale/si/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/sl/LC_MESSAGES/django.po | 1123 +++++++++-------- plinth/locale/sq/LC_MESSAGES/django.po | 1230 ++++++++++--------- plinth/locale/sr/LC_MESSAGES/django.po | 1123 +++++++++-------- plinth/locale/sv/LC_MESSAGES/django.po | 1209 +++++++++--------- plinth/locale/ta/LC_MESSAGES/django.po | 1110 ++++++++--------- plinth/locale/te/LC_MESSAGES/django.po | 1201 +++++++++--------- plinth/locale/tr/LC_MESSAGES/django.po | 1209 +++++++++--------- plinth/locale/uk/LC_MESSAGES/django.po | 1162 +++++++++--------- plinth/locale/vi/LC_MESSAGES/django.po | 1123 +++++++++-------- plinth/locale/zh_Hans/LC_MESSAGES/django.po | 1155 ++++++++--------- plinth/locale/zh_Hant/LC_MESSAGES/django.po | 1123 +++++++++-------- 40 files changed, 23100 insertions(+), 23073 deletions(-) diff --git a/plinth/locale/ar/LC_MESSAGES/django.po b/plinth/locale/ar/LC_MESSAGES/django.po index 6300d4ab1..0752eade6 100644 --- a/plinth/locale/ar/LC_MESSAGES/django.po +++ b/plinth/locale/ar/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-03-31 09:12+0000\n" "Last-Translator: abidin toumi \n" "Language-Team: Arabic calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1022,20 +1015,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1073,24 +1066,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1186,47 +1179,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1234,7 +1227,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1464,11 +1457,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1580,7 +1573,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1635,13 +1628,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1763,14 +1756,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1778,7 +1771,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1788,13 +1781,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1919,7 +1912,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1927,7 +1920,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1947,61 +1940,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2047,7 +2031,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2058,73 +2042,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2168,19 +2152,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2473,7 +2457,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2481,31 +2465,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2542,14 +2526,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2558,15 +2542,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2620,41 +2604,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2662,11 +2646,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2712,7 +2696,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2730,7 +2714,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2740,7 +2724,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2748,15 +2732,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2819,41 +2803,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2863,14 +2847,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2951,7 +2935,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2959,7 +2943,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2968,18 +2952,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3048,35 +3032,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3085,11 +3069,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3134,7 +3118,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3293,19 +3277,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3651,7 +3635,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3756,7 +3740,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3772,7 +3756,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3785,7 +3769,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4321,7 +4305,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4332,20 +4316,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4355,61 +4339,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4418,33 +4370,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4453,87 +4405,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4567,29 +4519,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4631,8 +4583,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4674,6 +4626,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4705,7 +4688,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4716,7 +4699,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4736,7 +4719,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4746,19 +4729,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4817,7 +4800,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4884,7 +4867,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4897,13 +4880,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4912,31 +4895,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5014,15 +4997,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5048,51 +5031,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5245,14 +5228,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5261,97 +5244,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5388,26 +5371,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5415,14 +5398,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5516,7 +5499,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5564,57 +5547,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5622,7 +5605,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5655,14 +5638,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5675,7 +5650,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5683,143 +5658,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5853,7 +5828,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5871,30 +5846,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5902,7 +5877,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5914,20 +5889,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5936,47 +5911,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6074,11 +6049,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6131,31 +6106,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6163,12 +6138,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6176,33 +6151,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6350,51 +6325,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6402,15 +6377,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6428,21 +6403,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6451,12 +6426,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6472,41 +6447,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6523,12 +6498,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6566,17 +6541,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6607,34 +6582,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6943,7 +6918,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6952,7 +6927,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6961,26 +6936,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6994,7 +6969,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7007,7 +6982,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7015,11 +6990,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7068,108 +7043,104 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "حدث خطأ أثناء تثبيت التطبيق: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "حدث خطأ أثناء تثبيت التطبيق: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "ثُبت التطبيق." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "حدث خطأ أثناء تثبيت التطبيق: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "ثُبت التطبيق." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7220,53 +7191,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/ar_SA/LC_MESSAGES/django.po b/plinth/locale/ar_SA/LC_MESSAGES/django.po index fb17132ed..1316ce4f9 100644 --- a/plinth/locale/ar_SA/LC_MESSAGES/django.po +++ b/plinth/locale/ar_SA/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2020-06-10 15:41+0000\n" "Last-Translator: aiman an \n" "Language-Team: Arabic (Saudi Arabia) calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1022,20 +1015,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1073,24 +1066,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1186,47 +1179,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1234,7 +1227,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1464,11 +1457,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1580,7 +1573,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1635,13 +1628,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1763,14 +1756,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1778,7 +1771,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1788,13 +1781,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1921,7 +1914,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1929,7 +1922,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1949,61 +1942,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2049,7 +2033,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2060,73 +2044,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2170,19 +2154,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2475,7 +2459,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2483,31 +2467,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2544,14 +2528,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2560,15 +2544,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2622,41 +2606,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2664,11 +2648,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2714,7 +2698,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2732,7 +2716,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2742,7 +2726,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2750,15 +2734,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2821,41 +2805,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2865,14 +2849,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2953,7 +2937,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2961,7 +2945,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2970,18 +2954,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3052,35 +3036,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3089,11 +3073,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3138,7 +3122,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3297,19 +3281,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3655,7 +3639,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3760,7 +3744,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3776,7 +3760,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3789,7 +3773,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4325,7 +4309,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4336,20 +4320,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4359,61 +4343,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4422,33 +4374,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4457,87 +4409,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4571,29 +4523,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4635,8 +4587,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4678,6 +4630,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4709,7 +4692,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4720,7 +4703,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4740,7 +4723,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4750,19 +4733,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4821,7 +4804,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4888,7 +4871,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4901,13 +4884,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4916,31 +4899,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5018,15 +5001,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5052,51 +5035,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5249,14 +5232,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5265,97 +5248,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5392,26 +5375,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5419,14 +5402,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5520,7 +5503,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5568,57 +5551,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5626,7 +5609,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5659,14 +5642,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5679,7 +5654,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5687,143 +5662,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5857,7 +5832,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5875,30 +5850,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5906,7 +5881,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5918,20 +5893,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5940,47 +5915,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6078,11 +6053,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6135,31 +6110,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6167,12 +6142,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6180,33 +6155,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6354,51 +6329,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6406,15 +6381,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6432,21 +6407,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6455,12 +6430,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6476,41 +6451,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6527,12 +6502,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6570,17 +6545,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6611,34 +6586,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6947,7 +6922,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6956,7 +6931,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6965,26 +6940,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6998,7 +6973,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7011,7 +6986,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7019,11 +6994,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7072,108 +7047,104 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "خطأ في تثبيت التطبيق :{string}{details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "خطأ في تثبيت التطبيق :{string}{details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "خطأ في تثبيت التطبيق:{error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "خطأ في تثبيت التطبيق:{error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "تم تثبيت التطبيق." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "خطأ في تثبيت التطبيق:{error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "خطأ في تثبيت التطبيق :{string}{details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "خطأ في تثبيت التطبيق:{error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "تم تثبيت التطبيق." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7224,53 +7195,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/bg/LC_MESSAGES/django.po b/plinth/locale/bg/LC_MESSAGES/django.po index 1aede025c..c5243a633 100644 --- a/plinth/locale/bg/LC_MESSAGES/django.po +++ b/plinth/locale/bg/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-10-01 13:58+0000\n" "Last-Translator: 109247019824 \n" "Language-Team: Bulgarian calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1042,7 +1035,7 @@ msgstr "" "Само букви от английската азбука, цифри, символите _ . и - без интервали и " "специални символи. Пример: My_Library_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1088,20 +1081,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1141,7 +1134,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1149,18 +1142,18 @@ msgstr "" "Тук можете да направите някои общи настройки, като име на хост, име на " "домейн, начална страница на сървъра и др." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Общи настройки" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Настройки" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1274,47 +1267,47 @@ msgstr "" "Дневникът съдържа информация, за това кой е достъпвал системата, както и " "информация от различни услуги за отстраняване на дефекти" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Грешка при задаване на името на хоста: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Името на хоста е зададено" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Грешка при задаване на името на домейна: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Името на домейна е зададено" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Грешка при задаване на началната страница на сървъра: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Началната страница на сървъра е зададена" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Грешка при промяна на разширения режим: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Разширените приложения и възможности се показват" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Разширените приложения и възможности са скрити" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1322,7 +1315,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1564,11 +1557,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1680,7 +1673,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1735,13 +1728,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client потребител с вход в " "{box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1868,14 +1861,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1883,7 +1876,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1893,13 +1886,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2026,7 +2019,7 @@ msgstr "Порт" msgid "Host/Target/Value" msgstr "Хост/цел/стойност" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2037,7 +2030,7 @@ msgstr "" "мрежов трафик в и от {box_name}. Поддържането на включена и правилно " "настроена защитна стена намалява риска от заплахи за сигурността от интернет." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Защитна стена" @@ -2057,53 +2050,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Порт {name} ({details}) недостъпен за външните мрежи" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Демонът на защитната стена не работи. Стартирайте го. Защитната стена на " -"%(box_name)s по подразбиране е включена. Всички системи на базата на Дебиан, " -"каквато е %(box_name)s, можете да я стартирате с командата „service " -"firewalld start“, а при устройства със systemd командата е „systemctl start " -"firewalld“." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Услуга/порт" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Включено" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Изключено" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Разрешено" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Разрешено (само вътрешни)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Разрешено (само външни)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Блокирано" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2113,13 +2092,13 @@ msgstr "" "бива разрешена и в защитната стена, а когато я спрете, тя бива забранена и в " "защитната стена." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Разширени" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2173,7 +2152,7 @@ msgstr "Начало на настройката" msgid "Setup Complete" msgstr "Настройката е завършена" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2184,73 +2163,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Обикновен хостинг на Git" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2294,19 +2273,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Хранилището е променено." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Промяна на хранилище" @@ -2606,7 +2585,7 @@ msgstr "Относно {box_name}" msgid "{box_name} Manual" msgstr "Руководство за {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2614,31 +2593,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2675,14 +2654,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2691,15 +2670,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2753,41 +2732,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2795,11 +2774,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2845,7 +2824,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2863,7 +2842,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2873,7 +2852,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2881,15 +2860,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Сертификати" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Не може да бъде извършена проба: Не са настроени домейни." @@ -2952,41 +2931,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2996,14 +2975,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3084,7 +3063,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3092,7 +3071,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3101,18 +3080,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3184,35 +3163,35 @@ msgstr "Паролата е променена" msgid "Password update failed. Please choose a stronger password" msgstr "Паролата не е променена. Изберете по-сложна парола" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Името на домейна е променено" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Името на страницата е променено" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3225,11 +3204,11 @@ msgstr "" "по подразбиране (30000). За да се свържете със сървъра, е необходим клиент за Minetest." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Пясъчник с блокове" @@ -3279,7 +3258,7 @@ msgstr "" msgid "Address" msgstr "Адрес" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3438,19 +3417,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3796,7 +3775,7 @@ msgstr "Редактиране на връзката" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Редактиране" @@ -3901,7 +3880,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3917,7 +3896,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3930,7 +3909,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Сигурност" @@ -4466,7 +4445,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4477,20 +4456,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4500,61 +4479,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4563,33 +4510,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4598,87 +4545,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4712,29 +4659,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4776,8 +4723,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Рестарт" @@ -4825,6 +4772,37 @@ msgstr "" msgid "Shut Down Now" msgstr "Изключване" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4856,7 +4834,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4867,7 +4845,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4887,7 +4865,7 @@ msgstr "" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4897,19 +4875,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Календар и адресна книга" @@ -4968,7 +4946,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Правата за достъп са променени" @@ -5045,7 +5023,7 @@ msgstr "" "RSS, за да следвате различни страници. При добавяне на емисия, включете " "удостоверяването и използвайте данните за вход на {box_name}." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Четене и абонамент за новинарски емисии" @@ -5058,13 +5036,13 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "Създател на емисии на RSS" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5073,31 +5051,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5175,15 +5153,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "Диск с OS на FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5209,51 +5187,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "Грешка при забраняване на споделянето: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5431,14 +5409,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5447,97 +5425,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5574,26 +5552,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5601,14 +5579,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5702,7 +5680,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5750,57 +5728,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Настройките на моментните снимки на хранилището са променени" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5808,7 +5786,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5841,14 +5819,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5861,7 +5831,7 @@ msgstr "Вход" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5869,143 +5839,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6039,7 +6009,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6057,30 +6027,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6088,7 +6058,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6100,20 +6070,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6122,7 +6092,7 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6131,40 +6101,40 @@ msgstr "" "На {box_name} е достъпен порт на Tor SOCKS за вътрешни мрежи на порт 9050 от " "TCP." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6270,11 +6240,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Настройките са променени" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Грешка при настройка на приложението: {error}" @@ -6334,14 +6304,14 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -6350,17 +6320,17 @@ msgstr "" "Ако е отметнато, достъп до Tiny Tiny RSS ще има всеки потребител, принадлежащ към групата feed-reader." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Четец на абонаменти за новини" @@ -6368,14 +6338,14 @@ msgstr "Четец на абонаменти за новини" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Проверява и прилага последните издания на софтуера и обновявания на " "сигурността." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6383,33 +6353,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Обновяване на софтуера" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox е обновен" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Обновяването на дистрибуцията не може да бъде стартирано" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6585,44 +6555,44 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Надграждане на дистрибуцията до тестова" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Честото обновяване на възможности е включено." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Начало на опит за обновяване на дистрибуцията." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -6633,7 +6603,7 @@ msgstr "" "получи достъп, някои приложения още имат изискване потребителският профил да " "бъде част от определена група." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6645,15 +6615,15 @@ msgstr "" "администратори могат да променят приложенията и настройките на " "системата." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Потребители и групи" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Достъп до всички услуги и системни настройки" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Проверете записа на LDAP „{search_item}“" @@ -6672,11 +6642,11 @@ msgid "" msgstr "" "Задължително. 150 знака или по-малко. Само латински букви, цифри и @/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Парола за удостоверяване" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -6684,11 +6654,11 @@ msgstr "" "За да разрешите промяната на профила, въведете паролата на потребителя " "„{user}“." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Грешна парола." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6697,12 +6667,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Не е създаден потребител в LDAP: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Новият потребител не е добавен към групата {group}: {error}" @@ -6722,41 +6692,41 @@ msgstr "" "няколко ключа, по един на ред. Празните редове и редовете, започващи с #, ще " "бъдат пренебрегнати." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Потребителят на LDAP не е преименуван." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Потребителят не е премахнат от групата." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Потребителят не е добавен към групата." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Ключовете на SSH не са зададени." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Състоянието на потребителя не е променено." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Паролата на потребителя на LDAP не е променена." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Новият потребител не е добавен към администраторската група: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Достъпът до конзолата не е ограничен: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Профилът е създаден и вече сте влезли" @@ -6773,12 +6743,12 @@ msgstr "Запазване на парола" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Създаване на потребител" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Премахване на потребител" @@ -6820,13 +6790,19 @@ msgid "The following administrator accounts exist in the system." msgstr "В системата съществуват следните администраторски профили." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "а да създадете профил, който може да се използва с %(box_name)s, премахнете " "тези профили от командния ред и презаредете страницата. Чрез командния ред " @@ -6835,7 +6811,7 @@ msgstr "" "прескочете тази стъпка." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Поребители" @@ -6868,34 +6844,34 @@ msgstr "" msgid "Save Changes" msgstr "Запазване на промените" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Потребителят %(username)s е създаден." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Потребителят %(username)s е променен." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Промяна на потребител" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Потребителят {user} е премахнат." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Потребителят на LDAP не е премахнат." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Промяна на парола" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Паролата е променена." @@ -7204,7 +7180,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7213,7 +7189,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7222,26 +7198,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7255,7 +7231,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7268,7 +7244,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7276,11 +7252,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7331,96 +7307,92 @@ msgstr "Изчакване да започне: {name}" msgid "Finished: {name}" msgstr "Готово: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Пакетът „{expression}“ е недостъпен за инсталиране" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Грешка при изпълняване на apt-get" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Времето за изчакване на диспечера на пакети е изтекло" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Инсталиране на приложение" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Обновяване на приложение" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Грешка при инсталиране на приложението: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Грешка при обновяване на приложението: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Грешка при инсталиране на приложението: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Грешка при обновяване на приложението: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "Приложението е инсталирано." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Приложението е обновено" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Премахване на приложение" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Грешка при премахване на приложението: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Грешка при премахване на приложението: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "Приложението е премахнато." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Обновяване на пакетите на приложението" @@ -7471,53 +7443,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "Услугата %(service_name)s не работи." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Начало" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Начало" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Приложения" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Приложения" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Системни" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Системни" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Смяна на парола" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Изключване" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Изход" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Избор на език" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Вход" @@ -7784,6 +7757,22 @@ msgstr "преди премахване на {app_id}" msgid "Gujarati" msgstr "Гуджарати" +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Демонът на защитната стена не работи. Стартирайте го. Защитната стена на " +#~ "%(box_name)s по подразбиране е включена. Всички системи на базата на " +#~ "Дебиан, каквато е %(box_name)s, можете да я стартирате с командата " +#~ "„service firewalld start“, а при устройства със systemd командата е " +#~ "„systemctl start firewalld“." + +#~ msgid "Error running apt-get" +#~ msgstr "Грешка при изпълняване на apt-get" + #~ msgid "Tor configuration is being updated" #~ msgstr "В момента настройките на Тор се обновяват" diff --git a/plinth/locale/bn/LC_MESSAGES/django.po b/plinth/locale/bn/LC_MESSAGES/django.po index ac1466ac6..2e8b51b6b 100644 --- a/plinth/locale/bn/LC_MESSAGES/django.po +++ b/plinth/locale/bn/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-06-16 07:33+0000\n" "Last-Translator: Oymate \n" "Language-Team: Bengali calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1021,20 +1014,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1072,24 +1065,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "কনফিগার" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1185,47 +1178,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1233,7 +1226,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1464,11 +1457,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1580,7 +1573,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1635,13 +1628,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ইজ্যাবার্ড" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1765,14 +1758,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1780,7 +1773,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1790,13 +1783,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1933,7 +1926,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1941,7 +1934,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "ফায়ারওয়্যাল" @@ -1961,61 +1954,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "সেবা/পোর্ট" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "সক্রিয়" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "নিষ্ক্রিয়" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "অনুমোদিত" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "অবরুদ্ধ" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2061,7 +2045,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2072,73 +2056,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2182,19 +2166,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2487,7 +2471,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2495,31 +2479,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2556,14 +2540,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2572,15 +2556,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ইকিউইকি" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2634,41 +2618,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2676,11 +2660,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "ইফিনোটেড" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2726,7 +2710,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2744,7 +2728,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2754,7 +2738,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2762,15 +2746,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "অনুমতিপত্র" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2833,41 +2817,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2877,14 +2861,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2965,7 +2949,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2973,7 +2957,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2982,18 +2966,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3064,35 +3048,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3101,11 +3085,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "মাইনটেস্ট" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3150,7 +3134,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3309,19 +3293,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3667,7 +3651,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3772,7 +3756,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3788,7 +3772,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3801,7 +3785,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4337,7 +4321,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4348,20 +4332,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4371,61 +4355,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4434,33 +4386,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4469,87 +4421,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4583,29 +4535,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4647,8 +4599,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4690,6 +4642,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4721,7 +4704,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4732,7 +4715,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4752,7 +4735,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4762,19 +4745,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4833,7 +4816,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4900,7 +4883,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4913,13 +4896,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4928,31 +4911,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5030,17 +5013,17 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "ফ্রিডমবক্স" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5066,51 +5049,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5263,14 +5246,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5279,97 +5262,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5406,26 +5389,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5433,14 +5416,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5534,7 +5517,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5582,57 +5565,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5640,7 +5623,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5673,14 +5656,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5693,7 +5668,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5701,143 +5676,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5871,7 +5846,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5889,30 +5864,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5920,7 +5895,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5932,20 +5907,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5954,47 +5929,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6092,13 +6067,13 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "Configuration" msgid "Updating configuration" msgstr "পছন্দসমূহ" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6150,31 +6125,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6182,12 +6157,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6195,33 +6170,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6369,51 +6344,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6421,15 +6396,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6447,21 +6422,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6470,12 +6445,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6491,41 +6466,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6542,12 +6517,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6585,17 +6560,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6626,34 +6601,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6962,7 +6937,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6971,7 +6946,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6980,26 +6955,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7013,7 +6988,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7026,7 +7001,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7034,11 +7009,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7087,96 +7062,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7227,53 +7198,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/cs/LC_MESSAGES/django.po b/plinth/locale/cs/LC_MESSAGES/django.po index 85518807a..8fdffcf32 100644 --- a/plinth/locale/cs/LC_MESSAGES/django.po +++ b/plinth/locale/cs/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-10-05 09:23+0000\n" "Last-Translator: Jiří Podhorecký \n" "Language-Team: Czech calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1034,23 +1027,23 @@ msgstr "" "K aplikaci budou mít přístup pouze uživatelé patřící do skupiny calibre. Všichni uživatelé s přístupem mohou používat všechny knihovny." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Použití knihoven e-knih Calibre" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Knihovna e-knih" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Název nové knihovny" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1058,7 +1051,7 @@ msgstr "" "Pouze písmena anglické abecedy, číslice a znaky _ . a - bez mezer a " "speciálních znaků. Příklad: My_Library_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Knihovna s tímto názvem již existuje." @@ -1106,20 +1099,20 @@ msgstr "Přejít do knihovny %(library)s" msgid "Delete library %(library)s" msgstr "Smazat knihovnu %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Knihovna vytvořena." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Při vytváření knihovny došlo k chybě." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} smazáno." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "{name} se nepodařilo smazat: {error}" @@ -1167,7 +1160,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Správa serveru" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1175,18 +1168,18 @@ msgstr "" "Zde můžete nastavit některé obecné konfigurační možnosti, jako je název " "hostitele, název domény, domovská stránka webového serveru atd." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Obecná nastavení" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Nastavit" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1300,47 +1293,47 @@ msgstr "" "Protokoly obsahují informace o tom, kdo přistupoval k systému, a informace o " "ladění různých služeb" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Chyba při nastavování názvu stroje: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Nastavení názvu stroje" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Chyba při nastavování doménového názvu: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Nastavení doménového názvu" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Chyba při nastavování domovské stránky webového serveru: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Nastavení domovské stránky webového serveru" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Chyba při změně pokročilého režimu: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Jsou zobrazovány pokročilé aplikace a funkce" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Jsou skryté pokročilé aplikace a funkce" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1352,7 +1345,7 @@ msgstr "" "komunikační servery jej mohou používat k navázání hovoru mezi stranami, " "které se jinak nemohou vzájemně spojit." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse nebo ejabberd je " "třeba nakonfigurovat pomocí zde uvedených údajů." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "Pomocník VoIP" @@ -1424,12 +1417,12 @@ msgstr "Chyba při nastavování časové zóny: {exception}" msgid "Time zone set" msgstr "Nastavení časové zóny" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "" "Deluge je BitTorrent klient který poskytuje webové uživatelské rozhraní." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1437,16 +1430,16 @@ msgstr "" "Výchozí heslo je \"deluge\", ale měli byste se přihlásit a změnit ho ihned " "po povolení této služby." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Stahovat soubory pomocí BitTorrent aplikací" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Webový klient sítě BitTorrent" @@ -1572,7 +1565,7 @@ msgstr "Výsledek" msgid "Diagnostic Test" msgstr "Diagnostické testy" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1583,7 +1576,7 @@ msgstr "" "každých 24 hodin), může být pro ostatní obtížné vás na internetu najít. To " "ostatním znemožní najít služby, které jsou poskytovány tímto {box_name}." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1600,7 +1593,7 @@ msgstr "" "váš název DNS k nové IP adrese, a pokud se někdo z Internetu zeptá na váš " "název DNS, dostane odpověď s vaší aktuální IP adresou." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1613,11 +1606,11 @@ msgstr "" "aktualizaci URL na adrese freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Klient dynamické DNS" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Název dynamické domény" @@ -1748,7 +1741,7 @@ msgstr "Toto pole je povinné." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1803,7 +1796,7 @@ msgstr "Server odmítl připojení" msgid "Already up-to-date" msgstr "Již aktualizováno" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1811,7 +1804,7 @@ msgstr "" "XMPP je otevřený a standardizovaný komunikační protokol. Zde je možné " "nastavit a spustit vlastní XMPP server, zvaný ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientuživatel s přihlašovacím " "jménem {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn nebo nakonfigurujte externí " "server." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Chat server" @@ -1961,7 +1954,7 @@ msgstr "" "%(domainname)s. Doménu je možné nastavit na stránce nastavení systému." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1972,7 +1965,7 @@ msgstr "" "klientům přistupovat k poštovní schránce pomocí protokolů IMAP a POP3. " "Rspamd se zabývá nevyžádanou poštou." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1984,7 +1977,7 @@ msgstr "" "internetových služeb také omezuje odchozí poštu. Někteří po výslovné žádosti " "omezení zruší. Další informace naleznete na stránce s manuálem." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1999,7 +1992,7 @@ msgstr "" "Potřebné aliasy, jako například \"postmaster\", se vytvoří automaticky a " "ukazují na prvního uživatele-administrátora." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2007,7 +2000,7 @@ msgstr "" "Aplikace Roundcube poskytuje " "uživatelům webové rozhraní pro přístup k e-mailu." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2138,7 +2131,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "Hostitel / cíl / hodnota" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2149,7 +2142,7 @@ msgstr "" "provoz na vašem {box_name}. Zapnutá a správně nastavená brána firewall " "snižuje riziko bezpečnostních hrozeb z Internetu." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Brána firewall" @@ -2169,53 +2162,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port {name} {details} je nedostupný pro externí sítě" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Proces služby brána firewall není spuštěný. Je třeba to napravit. Brána " -"firewall je na %(box_name)s ve výchozím stavu zapnutá. Na jakémkoli systému, " -"založeném na distribuci Debian (jako je i %(box_name)s) ji můžete spustit " -"příkazem „service firewalld start“ nebo v případě systému se systemd pomocí " -"„systemctl start firewalld“." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Služba/port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Zapnuto" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Vypnuto" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Umožněno" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Umožněno (pouze vnitřní)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Umožněno (pouze vnější)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Blokováno" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2225,13 +2204,13 @@ msgstr "" "také povolena na bráně firewall a když nějako službu vypnete, je také " "zakázána na bráně firewall." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Pokročilé" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2284,7 +2263,7 @@ msgstr "Spustit nastavení" msgid "Setup Complete" msgstr "Nastavení dokončeno" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2302,7 +2281,7 @@ msgstr "" "grafických klientů. A svoje zdrojové kódy můžete sdílet s lidmi z celého " "světa." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2310,67 +2289,67 @@ msgstr "" "Více o Git se dozvíte navštívením výuky Gitu." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Přístup do Git repozitářů pro čtení a zápis" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Jednoduché hostování Git" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Neplatné URL úložiště." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Neplatný název repozitáře." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "Název nového úložiště nebo adresa URL pro import stávajícího úložiště." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Popis repozitáře" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Volitelné, zobrazuje se na Gitwebu." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Jméno vlastníka repozitáře" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Neveřejný repozitář" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "K tomuto repozitáři umožnit přístup pouze pověřeným uživatelům." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Repozitář s tímto názvem už existuje." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Název repozitáře" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "Řetězec písmeny a číslicemi, který jednoznačně identifikuje repozitář." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Výchozí větev" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb ji zobrazí jako výchozí větev." @@ -2414,19 +2393,19 @@ msgstr "Smazat Git repozitář %(name)s" msgid "Delete this repository permanently?" msgstr "Nevratně smazat tento repozitář?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Repozitář vytvořen." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Při vytváření úložiště došlo k chybě." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Repozitář upraven." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Upravit repozitář" @@ -2786,7 +2765,7 @@ msgstr "O {box_name}" msgid "{box_name} Manual" msgstr "Příručka k {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2798,7 +2777,7 @@ msgstr "" "anonymitu posíláním provozu zašifrovaně, skrze dobrovolníky provozovanou síť " "rozprostřenou po celém světě." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2806,26 +2785,26 @@ msgstr "" "Více informací I2P naleznete na domovské stránce projektu." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" "První navštívení poskytovaného webového rozhraní spustí proces nastavení." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Spravovat aplikaci I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Anonymní síť" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P proxy" @@ -2870,7 +2849,7 @@ msgstr "" "Soubory stahujete přidáním torrentů nebo vytvořením nového torrentu a " "sdílením souboru skrze něj." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2880,7 +2859,7 @@ msgstr "" "značkovacích jazyků, včetně Markdown, a běžné blogovací funkce, jako jsou " "komentáře a RSS kanály." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2893,15 +2872,15 @@ msgstr "" "může upravovat ty stávající. V Nastavení " "uživatele můžete tato oprávnění změnit nebo přidat nové uživatele." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "wiki a blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Zobrazit a upravit wiki aplikace" @@ -2957,42 +2936,42 @@ msgstr "" "Tato akce odebere veškeré příspěvky, stránky a komentáře včetně historie " "verzí. Opravdu chcete nenávratně smazat tuto wiki/blog?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Wiki {name} vytvořena." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Wiki se nepodařilo vytvořit: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Blog {name} vytvořen." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Blog se nepodařilo vytvořit: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} dsmazáno." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "{title} se nepodařilo smazat: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" "infinoted je server pro Gobby – textový editor pro spolupráci ve skupině." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3003,11 +2982,11 @@ msgstr "" "desktopového klienta a nainstalujte ho. Poté spusťte Gobby a zvolte " "„Připojit k serveru“ a zadejte doménový název svého {box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby server" @@ -3056,7 +3035,7 @@ msgstr "Janus Video Room" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Licenční informace o JavaScriptu" @@ -3076,7 +3055,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Chatovací klient" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3091,7 +3070,7 @@ msgstr "" "dokázáním, že je vlastníkem domény vůči Let's Encrypt, certifikační autoritě " "(CA)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3103,15 +3082,15 @@ msgstr "" "(ISRG). Před použitím služby si přečtěte Podmínky používání Let's Encrypt." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Certifikáty" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Nelze testovat: Nejsou nakonfigurovány žádné domény." @@ -3176,7 +3155,7 @@ msgstr "" "Nejsou nastavené žádné domény. Nastavte je, " "aby bylo možné pro ně získat certifikát." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3185,34 +3164,34 @@ msgstr "" "Platnost certifikátu pro doménu {domain} úspěšně odvolána. Může to chvíli " "trvat, než se změna projeví." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Nepodařilo se odvolat platnost certifikátu prodoménu {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Úspěšně obdržen certifikát pro doménu {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Nepodařilo se získat certifikát pro doménu {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Certifikát pro doménu {domain} úspěšně smazán" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Nepodařilo se smazat certifikát pro doménu {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3229,7 +3208,7 @@ msgstr "" "čísla. Díky federování mohou uživatelé na daném Matrix serveru komunikovat s " "uživateli všech ostatních Matrix serverů." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3239,7 +3218,7 @@ msgstr "" "Nainstalujte aplikaci Coturn nebo " "nakonfigurujte externí server." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3347,7 +3326,7 @@ msgstr "" "Pro jeho získání přejděte na stránku Let's " "Encrypt." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3359,7 +3338,7 @@ msgstr "" "skupině. Mediawiki je možné použít pro hostování wiki webových stránek, " "poznámek nebo pro spolupráci s přáteli na projektech." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3373,7 +3352,7 @@ msgstr "" "stránce Special:" "CreateAccount." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3381,12 +3360,12 @@ msgstr "" "Kdokoli kdo má odkaz na tuto wiki ji může číst. Měnit obsah mohou pouze " "uživatelé, kteří jsou přihlášení." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3467,35 +3446,35 @@ msgstr "Heslo aktualizováno" msgid "Password update failed. Please choose a stronger password" msgstr "Aktualizace hesla se nezdařila. Zvolte prosím silnější heslo" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Registrace pro veřejnost otevřené" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Registrace pro veřejnost zavřené" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Soukromý režim zapnut" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Soukromý režim vypnut" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Změna výchozího vzhledu" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Nastavení doménového názvu aktualizováno" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Název webu aktualizován" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3508,11 +3487,11 @@ msgstr "" "serveru je třeba Minetest " "klient." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Pískoviště s kostkami" @@ -3561,7 +3540,7 @@ msgstr "Pokud je vypnuto, postavy hráčů nemohou zemřít nebo se zranit." msgid "Address" msgstr "Adresa" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3747,7 +3726,7 @@ msgstr "Zabezpečený shell" msgid "Services" msgstr "Služby" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3755,7 +3734,7 @@ msgstr "" "Nastavit síťová zařízení. Připojit k Internetu přes ethernet, WiFi nebo " "PPPoE. Sdílet toto připojení s ostatními zařízeními na síti." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3763,7 +3742,7 @@ msgstr "" "Zařízení spravovaná jinými metodami zde nemusí být k dispozici pro " "konfiguraci." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Sítě" @@ -4193,7 +4172,7 @@ msgstr "Upravit připojení" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Upravit" @@ -4298,7 +4277,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Metoda" @@ -4314,7 +4293,7 @@ msgstr "DNS server" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Výchozí" @@ -4327,7 +4306,7 @@ msgid "This connection is not active." msgstr "Toto připojení není aktivní." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Zabezpečení" @@ -4915,7 +4894,7 @@ msgstr "Připojení {name} smazáno." msgid "Failed to delete connection: Connection not found." msgstr "Smazání připojení se nezdařilo: Připojení nenalezeno." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4932,20 +4911,20 @@ msgstr "" "zvýšení zabezpečení a anonymity je také možné přistupovat k ostatku " "Internetu prostřednictvím {box_name}." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Připojení ke službám VPN" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Virtuální soukromá síť" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4956,58 +4935,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Migrace na ECC" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Vaše instalace OpenVPN v současné době používá RSA. Přechod na moderní " -"kryptografii eliptických křivek zvyšuje rychlost navázání spojení a " -"bezpečnost. Tato operace je nevratná. Na většině jednodeskových počítačů by " -"měla trvat jen několik minut." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Všechny nové instalace OpenVPN na %(box_name)s budou ve výchozím nastavení " -"používat ECC. Doporučujeme provést migraci co nejdříve." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Upozornění: Stávající klientské profily budou touto operací " -"zneplatněny. Všichni uživatelé OpenVPN na %(box_name)s si musí stáhnout nové " -"profily. Pro připojení k tomuto serveru by měli být použiti klienti OpenVPN " -"kompatibilní s ECC." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Migrace" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Chcete-li se připojit k síti VPN společnosti %(box_name)s, musíte si " @@ -5016,18 +4958,19 @@ msgstr "" "Doporučené klienty a pokyny k jejich konfiguraci najdete po kliknutí na " "\"Další informace...\" výše." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Profil je specifický každému z uživatelů %(box_name)s. Uchovejte ho v " "tajnosti." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Stáhnout si svůj profil" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5040,19 +4983,19 @@ msgstr "" "{box_name} nejsou dostupné ze zbytku internetu. To zahrnuje následující " "situace:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} se nachází za omezující bránou firewall." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} je připojený k (bezdrátovému) směrovači, který není ve vaší " "správě." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5060,7 +5003,7 @@ msgstr "" "Váš poskytovatel připojení vám neposkytuje vnější (veřejnou) IP adresu a " "namísto toho poskytuje připojení prostřednictvím NAT překladu." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5068,11 +5011,11 @@ msgstr "" "Váš poskytovatel připojení vám neposkytuje pevnou IP adresu a ta se proto " "mění pokaždé, když se připojíte k Internetu." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Váš poskytovatel připojení k Internetu omezuje příchozí spojení." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5085,23 +5028,23 @@ msgstr "" "pagekite, například pagekite.net. V " "budoucnu bude možná možné k tomuto účelu použít {box_name} vašeho kamaráda." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Viditelnost na veřejnosti" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite doména" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Doména serveru" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5109,31 +5052,31 @@ msgstr "" "Vyberte pagekite server, který chcete používat. Pokud to má být ten výchozí, " "zadejte „pagekite.net“." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Port serveru" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Port pagekite serveru (výchozí: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite název" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Příklad: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Neplatný kite název" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite heslo" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5141,35 +5084,35 @@ msgstr "" "Heslo přiřazené ke kite nebo výchozí heslo pro váš účet pokud není na kite " "žádné nastavené." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protokol" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "vnější (frontend) port" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "vnitřní (freedombox) port" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Zapnout podřízené domény" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Uživatelem určená služba smazána" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Tato služba je již k dispozici jako standardní služba." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Uživatelem určená služba přidána" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Tato služba už existuje" @@ -5206,29 +5149,29 @@ msgstr "" "kombinace protokol/port, které zde můžete určit. Například o HTTPS na portu " "jiném, než 443 je známo, že způsobuje problémy." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Webový server (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Stránky budou k dispozici na http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Webový server (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Stránky budou k dispozici na https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Zabezpečený shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5279,8 +5222,8 @@ msgstr "" "Nyní je spuštěná instalace nebo přechod na novější verzi. Počkejte s vypínám " "či restartem na dokončení této operace." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Restartovat" @@ -5329,6 +5272,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Vypnout nyní" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5368,7 +5344,7 @@ msgstr "Webová proxy" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Přistupte {url} s proxy {proxy} na tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5385,7 +5361,7 @@ msgstr "" "více Quassel klientů z desktopu nebo mobilu může být použito pro připojení " "nebo odpojení od něj." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your desktopu a mobilních zařízení." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC klient" @@ -5409,7 +5385,7 @@ msgstr "IRC klient" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5424,7 +5400,7 @@ msgstr "" "\">podporovaná klientská aplikace. K Radicale má přístup každý uživatel " "s přihlašovacím jménem {box_name}." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5434,12 +5410,12 @@ msgstr "" "nových kalendářů a adresářů kontaktů. Nepodporuje přidávání událostí či " "kontaktů, to je třeba dělat v tomu určeném klientovi." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Kalendář a adresář kontaktů" @@ -5513,7 +5489,7 @@ msgstr "" "své uživatelské jméno. Po kliknutí na tlačítko vyhledávání se zobrazí seznam " "existujících kalendářů a adresářů." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Nastavení přístupových práv aktualizováno" @@ -5606,7 +5582,7 @@ msgstr "" "sledování různých webových stránek. Při přidávání kanálu povolte ověřování a " "použijte své přihlašovací údaje {box_name}." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Číst a přihlásit se k odběru novinek" @@ -5619,7 +5595,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "Generátor kanálů RSS" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5627,7 +5603,7 @@ msgstr "" "Samba umožňuje sdílet soubory a složky mezi zařízením FreedomBox a ostatními " "počítači v místní síti." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5640,11 +5616,11 @@ msgstr "" "\\{hostname} (v systému Windows) nebo smb://{hostname}.local (v systémech " "Linux a Mac). Na výběr jsou tři typy sdílených složek: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Otevřené sdílení - přístupné všem v místní síti." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5652,7 +5628,7 @@ msgstr "" "Sdílení ve skupině - přístupné pouze uživatelům FreedomBoxu, kteří jsou ve " "skupině freedombox-share." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5660,15 +5636,15 @@ msgstr "" "Domácí sdílení - každý uživatel ve skupině freedombox-share může mít svůj " "vlastní soukromý prostor." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Přístup k soukromému sdílení" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Distribuované souborové úložiště" @@ -5757,15 +5733,15 @@ msgstr "Sdílet název" msgid "Action" msgstr "Akce" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS disk" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Otevřít sdílení" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Skupinové sdílení" @@ -5791,7 +5767,7 @@ msgstr "Sdílení upraveno." msgid "Error disabling share: {error_message}" msgstr "Chyba při zakázání sdílení: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5799,7 +5775,7 @@ msgstr "" "Searx je soukromí respektující metavyhledavač na Internetu. Slučuje a " "zobrazuje výsledky z vícero vyhledávačů." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5807,39 +5783,39 @@ msgstr "" "Použitím Searx je možné se vyhnout sledování a profilování vyhledávači. Ve " "výchozím stavu neukládá žádné cookie." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Hledat na webu" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Vyhledávání na webu" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Bezpečné vyhledávání" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "Vyberte výchozí dětský filtr který uplatnit na výsledky vyhledávání." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Střední" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Přísný" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Umožnit veřejný přístup" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Umožnit, aby tato aplikace byla používána kýmkoli, kdo se k ní může dostat." @@ -6019,7 +5995,7 @@ msgstr "Záložky" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6029,7 +6005,7 @@ msgstr "" "vašeho Internetového provozu. Je možné ji použít pro obejití filtrování " "Internetu a cenzury." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6042,7 +6018,7 @@ msgstr "" "připojit k této proxy a jejich data budou šifrována a posílána " "prostřednictvím Shadowsocks serveru." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6050,43 +6026,43 @@ msgstr "" "Pro použití Shadowsocks po nastavení, nastavte SOCKS5 proxy URL adresu ve " "svém zařízení, prohlížeči nebo aplikaci na http://adresa_freedombox:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Socks5 proxy" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Doporučeno" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Server" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Název nebo IP adresa serveru" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Číslo portu serveru" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Heslo sloužící pro šifrování dat. Je třeba, aby se shodovalo s heslem " "serveru." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" "Metoda šifrování. Je třeba, aby byla stejná, jaká je nastavená na serveru." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6095,15 +6071,15 @@ msgstr "" "Sdílení umožňuje sdílet soubory a složky na vašem {box_name} přes web se " "zvolenou skupinou uživatelů." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Sdílení" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Název sdílení" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6111,29 +6087,29 @@ msgstr "" "Řetězec malými písmeny a číslicemi který jednoznačně identifikuje sdílení. " "Příklad:média." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Popis umístění které sdílet" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" "Popis umístění složky na datovém úložišti tohoto serveru které zamýšlíte " "sdílet." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Veřejné sdílení" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Zpřístupnit soubory v této složce všem, kteří mají odkaz." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Skupina uživatelů která může číst soubory na sdílení:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6141,11 +6117,11 @@ msgstr "" "Uživatelé vybraných skupin uživatelů budou moci číst soubory ve sdílené " "složce." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Sdílení s tímto názvem už existuje." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" "Sdílení by mělo být buď veřejné, nebo sdílené alespoň s jednou skupinou." @@ -6183,19 +6159,19 @@ msgstr "Sdílení přidáno." msgid "Add Share" msgstr "Přidat sdílení" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Sdílení upraveno." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Upravit sdílení" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Sdílení smazáno." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6205,7 +6181,7 @@ msgstr "" "souborového systému btrfs. Ty je možné použít pro vrácení systému do " "dřívějšího funkčního stavu v případě nechtěných změn." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6216,7 +6192,7 @@ msgstr "" "osy) a také před a po instalaci software. Nejstarší zachycené stavy budou " "automaticky mazány podle níže uvedených nastavení." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups, protože mohou být ukládány pouze na stejném oddílu, " "jako živá data. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Zachycené stavy datového úložiště" @@ -6330,7 +6306,7 @@ msgstr "Datum" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Smazat zachycené stavy" @@ -6383,57 +6359,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Vrátit k zachycenému stavu č. %(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "ručně vytvořen" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "časová osa" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Spravovat zachycené stavy" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Zachycený stav pořízen." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Nastavení zachycování stavů úložiště aktualizováno" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Chyba akce: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Označené zachycené stavy smazány" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Zachycený stav je používán. Zkuste to později." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Vráceno zpět do podoby zachyceného stavu č. {number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Pro dokončení obnovy ze zálohy je třeba systém restartovat." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Vrátit do podoby zachyceného stavu" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6445,7 +6421,7 @@ msgstr "" "spojení provádět úkoly správy, kopírovat soubory nebo spouštět ostatní " "služby." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Server zabezpečeného shellu (SSH)" @@ -6483,16 +6459,6 @@ msgstr "Algoritmus" msgid "Fingerprint" msgstr "Otisk (fingerprint)" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" -"Při připojování k serveru se ujistěte, že otisk prstu zobrazený klientem SSH " -"odpovídá jednomu z těchto otisků. Ověřování SSH s vypnutým heslem." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "Ověřování SSH s povoleným heslem." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Sdružené přihlášení (SSO)" @@ -6505,7 +6471,7 @@ msgstr "Přihlášení" msgid "Logged out successfully." msgstr "Odhlášení proběhlo úspěšně." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6516,105 +6482,105 @@ msgstr "" "{box_name}. Lze zobrazit úložná zařízení, která jsou využívána, připojovat a " "odpojovat ta vyjímatelná." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Úložiště" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bajtů" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Operace se nezdařila." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Operace byla zrušena." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Toto zařízení už je odpojováno (umount)." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "Operace není podporována z důvodu chybějící podpory ovladače/nástroje." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Časový limit aplikace překročen." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "Operace by probudila disk který je v režimu hlubokého spánku." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Pokus o odpojení zařízení které je zaneprázdněno." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Operace už byla zrušena." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Chybí oprávnění pro provedení požadované operace." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Toto zařízení je už připojeno (mount)." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Zařízení není připojeno." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Není umožněno použít požadovanou volbu." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Zařízení je připojeno jiným uživatelem." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Málo místa na systémovém oddílu: {percent_used}% použito, {free_space} volné." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Málo místa na disku" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Hrozí selhání disku" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6623,39 +6589,39 @@ msgstr "" "Disk {id} hlásí, že v blízké budoucnosti pravděpodobně selže. Zkopírujte " "všechna data, dokud to ještě jde, a disk vyměňte." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Neplatný název adresáře." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Adresář neexistuje." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Cesta není adresář." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Adresář není pro uživatele čitelný." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Do adresáře nemůže uživatel zapisovat." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Adresář" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Podadresář (volitelné)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Sdílet" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Jiný adresář (uveďte níže)" @@ -6692,7 +6658,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Zvětšit kořenový oddíl" @@ -6714,30 +6680,30 @@ msgstr "" "Než budete pokračovat, zazálohujte svá data. Po provedení této operace na " "kořenovém oddílu bude k dispozici %(expandable_root_size)s dalšího prostoru." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Chyba při zvětšování oddílu: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Oddíl úspěšně zvětšen." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} je možné bezpečně odebrat." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Zařízení je možné bezpečně odebrat." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Chyba při vysouvání zařízení: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6749,7 +6715,7 @@ msgstr "" "smazání souborů na jednom zařízení bude automaticky replikováno na veškerá " "zařízení, na kterých také provozujete Syncthing." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6768,20 +6734,20 @@ msgstr "" "na {box_name} je dostupné pouze pro uživatele patřící do skupiny \"admin\" " "nebo \"syncthing-access\"." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Spravovat aplikaci Syncthing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Synchronizace souborů" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6795,7 +6761,7 @@ msgstr "" "prohlížeč Tor Browser." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6804,40 +6770,40 @@ msgstr "" "Tor SOCKS port je k dispozici na vašem {box_name} pro interní síť na TCP " "portu 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor Onion Service" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor Socks proxy" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Předávájící Tor most" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Port Tor předávání k dispozici" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 transport zaregistrován" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 transport zaregistrován" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Přistoupit k URL adrese {url} na tcp{kind} prostřednictvím Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Potvrďte použití Tor na adrese {url} na tcp{kind}" @@ -6954,11 +6920,11 @@ msgstr "Onion služba" msgid "Ports" msgstr "Porty" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Aktualizace konfigurace" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Chyba při konfiguraci aplikace: {error}" @@ -7022,7 +6988,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7031,7 +6997,7 @@ msgstr "" "Tiny Tiny RSS je čtečka a slučovač novinek (RSS/Atom), navržená pro čtení " "odkudkoli, ale s pohodlím podobným desktopové aplikaci." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7040,7 +7006,7 @@ msgstr "" "Pokud je funkce Tiny Tiny RSS povolena, může k ní přistupovat každý uživatel patřící do skupiny feed-reader." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7048,11 +7014,11 @@ msgstr "" "Při použití mobilní nebo desktopové aplikace pro Tiny Tiny RSS použijte pro " "připojení adresu URL /tt-rss-app." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Čtečka novinek" @@ -7060,13 +7026,13 @@ msgstr "Čtečka novinek" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Zjistit dostupnost a uplatnit nejnovější aktualizace a opravy zabezpečení." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7079,22 +7045,22 @@ msgstr "" "systému považován za nezbytný, provede se automaticky ve 02:00 a způsobí, že " "všechny aplikace budou krátce nedostupné." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Aktualizace software" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox aktualizován" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Nelze spustit aktualizaci distribuce" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7104,11 +7070,11 @@ msgstr "" "distribuce. Zajistěte, aby bylo volných alespoň 5 GB. Aktualizace distribuce " "se bude opakovat po 24 hodinách, pokud je povolena." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Zahájena aktualizace distribuce" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7281,44 +7247,44 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Otestujte aktualizaci distribuce" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Chyba při nastavování bezobslužných aktualizací: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Automatické aktualizace zapnuty" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Automatické aktualizace vypnuty" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Upgrade distribuce povoleno" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Upgrade distribuce zakázáno" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Proces přechodu na novější verze zahájen." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Spouštění přechodu na novější verzi se nezdařilo." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Aktivovány časté aktualizace funkcí." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Zahájení testu aktualizace distribuce." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7329,7 +7295,7 @@ msgstr "" "aby uživatelský účet byl součástí skupiny, která uživatele opravňuje k " "přístupu k aplikaci." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7341,15 +7307,15 @@ msgstr "" "nebo nastavení systému však mohou měnit pouze uživatelé skupiny admin." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Uživatelé a skupiny" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Přístup ke všem službám a nastavení systému" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Zkontrolujte LDAP položku „{search_item}“" @@ -7369,21 +7335,21 @@ msgid "" msgstr "" "Požadováno. Nejvýše 150 znaků. Pouze anglická písmena, číslice a @/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Autorizační heslo" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "Zadejte heslo uživatele \"{user}\" pro autorizaci změn účtu." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Neplatné heslo." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7397,12 +7363,12 @@ msgstr "" "skupině admin se budou moci přihlásit ke všem službám. Mohou se také " "přihlašovat do systému prostřednictvím SSH a mají práva správce (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Vytvoření uživatele LDAP se nezdařilo: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Nepodařilo se přidat nového uživatele do skupiny {group}: {error}" @@ -7421,41 +7387,41 @@ msgstr "" "systému i bez zadávání hesla. Klíčů je možné vložit vícero, každý na vlastní " "řádek. Prázdné řádky a ty, které začínají na znak # budou ignorovány." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Přejmenování LDAP uživatele se nezdařilo." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Odebrání uživatele ze skupiny se nezdařilo." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Přidání uživatele do skupiny se nezdařilo." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Nepodařilo se vložit SSH klíče." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Nepodařilo se změnit stav uživatele." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Změna hesla LDAP uživatele se nezdařila." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Nepodařilo se přidat nového uživatele do skupiny admin: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Nepodařilo se omezit přístup ke konzole: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Uživatelský účet vytvořen, není jste jím přihlášeni" @@ -7472,12 +7438,12 @@ msgstr "Uložit heslo" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Vytvořit uživatele" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Smazat uživatele" @@ -7518,13 +7484,19 @@ msgid "The following administrator accounts exist in the system." msgstr "V systému existují následující účty správců." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Odstraňte tyto účty z příkazového řádku a obnovte stránku, abyste vytvořili " "účet, který je použitelný s %(box_name)s. V příkazovém řádku spusťte příkaz " @@ -7533,7 +7505,7 @@ msgstr "" "přeskočte." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Uživatelé" @@ -7566,34 +7538,34 @@ msgstr "" msgid "Save Changes" msgstr "Uložit změny" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Uživatel %(username)s vytvořen." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Uživatel %(username)s aktualizován." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Upravit uživatele" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Uživatel {user} smazán." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Smazání LDAP uživatele se nezdařilo." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Změnit heslo" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Heslo úspěšně změněno." @@ -7928,7 +7900,7 @@ msgstr "Odstranit připojení k serveru" msgid "Server deleted." msgstr "Server smazán." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7942,7 +7914,7 @@ msgstr "" "Administrační rozhraní a vytvořené webové stránky jsou vhodné pro mobilní " "zařízení." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7955,7 +7927,7 @@ msgstr "" "názvem domény. Povolte trvalé odkazy v rozhraní správce pro lepší adresy URL " "vašich stránek a příspěvků." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -7966,7 +7938,7 @@ msgstr "" "přidejte si stranu administrace do " "záložek." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -7976,12 +7948,12 @@ msgstr "" "rozhraní správce. Další zásuvné moduly nebo témata lze instalovat a " "aktualizovat na vlastní riziko." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Webové stránky a blog" @@ -7998,7 +7970,7 @@ msgstr "" "WordPress pouze správcům. Povolte pouze po provedení počátečního nastavení " "WordPressu." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8020,7 +7992,7 @@ msgstr "" "určitém místě. Jednotlivé fotografie lze sdílet s ostatními odesláním " "přímého odkazu." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8031,11 +8003,11 @@ msgstr "" "další uživatele musí být vytvořeny účty jak v {box_name}, tak v Zoph se " "stejným uživatelským jménem." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Organizér fotografií" @@ -8088,96 +8060,92 @@ msgstr "Čeká na spuštění: {name}" msgid "Finished: {name}" msgstr "Dokončeno: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Balíček {expression} není k dispozici pro instalaci" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Balíček {package_name} je nejnovější verze ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Chyba při spuštění apt-get" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "Instalace" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "stahování" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "změna média" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "soubor s nastaveními: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Časový limit čekání na správce balíčků" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Instalace aplikací" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Aktualizace aplikací" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Chyba instalace aplikace: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Chyba aktualizace aplikace: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Chyba při instalaci aplikace: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Chyba při aktualizaci aplikace: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "Aplikace nainstalována." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Aplikace aktualizována" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Odinstalování aplikace" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Chyba odinstalace aplikace: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Chyba při odinstalaci aplikace: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "Aplikace odinstalována." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Aktualizace balíčků aplikací" @@ -8235,53 +8203,54 @@ msgstr "Instalace" msgid "Service %(service_name)s is not running." msgstr "Služba %(service_name)s není spuštěná." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Základní funkce a webové rozhraní pro %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Domů" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Domů" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Aplikace" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Aplikace" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Systém" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Systém" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Změnit heslo" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Vypnout" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Odhlásit" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Vyberte jazyk" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Přihlásit" @@ -8571,6 +8540,77 @@ msgstr "před odinstalací {app_id}" msgid "Gujarati" msgstr "gudžarátština" +#~ msgid "Enable DNSSEC" +#~ msgstr "Zapnout DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Zapnout zabezpečovací rozšíření systému doménových názvů" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Proces služby brána firewall není spuštěný. Je třeba to napravit. Brána " +#~ "firewall je na %(box_name)s ve výchozím stavu zapnutá. Na jakémkoli " +#~ "systému, založeném na distribuci Debian (jako je i %(box_name)s) ji " +#~ "můžete spustit příkazem „service firewalld start“ nebo v případě systému " +#~ "se systemd pomocí „systemctl start firewalld“." + +#~ msgid "Migrate to ECC" +#~ msgstr "Migrace na ECC" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Vaše instalace OpenVPN v současné době používá RSA. Přechod na moderní " +#~ "kryptografii eliptických křivek zvyšuje rychlost navázání spojení a " +#~ "bezpečnost. Tato operace je nevratná. Na většině jednodeskových počítačů " +#~ "by měla trvat jen několik minut." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Všechny nové instalace OpenVPN na %(box_name)s budou ve výchozím " +#~ "nastavení používat ECC. Doporučujeme provést migraci co nejdříve." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Upozornění: Stávající klientské profily budou touto operací " +#~ "zneplatněny. Všichni uživatelé OpenVPN na %(box_name)s si musí stáhnout " +#~ "nové profily. Pro připojení k tomuto serveru by měli být použiti klienti " +#~ "OpenVPN kompatibilní s ECC." + +#~ msgid "Migrate" +#~ msgstr "Migrace" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "" +#~ "Při připojování k serveru se ujistěte, že otisk prstu zobrazený klientem " +#~ "SSH odpovídá jednomu z těchto otisků. Ověřování SSH s vypnutým heslem." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Ověřování SSH s povoleným heslem." + +#~ msgid "Error running apt-get" +#~ msgstr "Chyba při spuštění apt-get" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Základní funkce a webové rozhraní pro %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Síťová připojení" diff --git a/plinth/locale/da/LC_MESSAGES/django.po b/plinth/locale/da/LC_MESSAGES/django.po index fdebd06e0..f10c4e811 100644 --- a/plinth/locale/da/LC_MESSAGES/django.po +++ b/plinth/locale/da/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Danish calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1049,29 +1042,29 @@ msgstr "" "Kun brugere der tilhører calibre-gruppen har adgang til appen. Alle " "brugere med adgang kan benytte alle samlingerne." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Brug calibre e-bogssamlinger" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "E-bogssamling" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Den nye samlings navn" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "En samling med dette navn eksisterer allerede." @@ -1119,20 +1112,20 @@ msgstr "Tilgå samlingen %(library)s" msgid "Delete library %(library)s" msgstr "Slet samlingen %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Samling oprettet." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Der opstod en fejl under oprettelse af samlingen." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} slettet." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Kunne ikke slette {name}: {error}" @@ -1180,7 +1173,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Serveradministration" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1188,18 +1181,18 @@ msgstr "" "Her kan du konfigurere nogle generelle indstillinger såsom værtsnavn, " "domænenavn, webserverens hjemmeside osv." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Generel Konfiguration" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Konfigurer" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1312,47 +1305,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Kunne ikke sætte værtsnavn: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Værtsnavn gemt" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Kunne ikke sætte domænenavn: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Domænenavn gemt" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Fejl ved indstilling af webserverens hjemmeside: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Webserverens hjemmeside er blevet indstillet" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Fejl ved skift til avanceret tilstand: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Viser avancerede applikationer og funktionalitet" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Skjuler avancerede applikationer og funktionalitet" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1364,7 +1357,7 @@ msgstr "" "WebRTC, SIP og andre kommunikationsservere kan bruge dette til at oprette et " "opkald mellem parter der ellers ikke kan oprette forbindelse til hinanden." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, fuzzy, python-brace-format #| msgid "" #| "It is not meant to be used directly by users. Servers such as matrix-" @@ -1377,11 +1370,11 @@ msgstr "" "Den er ikke beregnet til at blive anvendt direkte af brugerne. Servere såsom " "matrix-synapse skal konfigureres med detaljerne som er angivet her." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP-hjælper" @@ -1439,11 +1432,11 @@ msgstr "Kunne ikke sætte tidszone: {exception}" msgid "Time zone set" msgstr "Tidszone gemt" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge er en BitTorrent-klient som har et webbaseret brugerinterface." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1451,16 +1444,16 @@ msgstr "" "Standardkodeordet er 'deluge', men du bør logge ind og ændre det så snart du " "har aktiveret denne tjeneste." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Download filer ved hjælp af BitTorrent-applikationer" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent Webklient" @@ -1587,7 +1580,7 @@ msgstr "Resultat" msgid "Diagnostic Test" msgstr "Diagnostisk Test" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1598,7 +1591,7 @@ msgstr "" "døgnet), kan det være svært for andre at finde dig på internettet. Dette vil " "forhindre andre i at finde de tjenester denne {box_name} udbyder." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1615,7 +1608,7 @@ msgstr "" "opdatere dit DNS-navn med den nye IP-adresse, således at hvis nogen på " "internettet spørger til adressen vil de få din aktuelle IP-adresse." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 #, fuzzy #| msgid "" #| "If you are looking for a free dynamic DNS account, you may find a free " @@ -1634,11 +1627,11 @@ msgstr "" "datasystems24.net eller du kan få en gratis URL-baseret tjeneste på freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Dynamisk DNS Klient" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Dynamisk domænenavn" @@ -1772,7 +1765,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1841,7 +1834,7 @@ msgstr "Slet forbindelse" msgid "Already up-to-date" msgstr "Seneste opdatering" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1849,7 +1842,7 @@ msgstr "" "XMPP er en åben og standardiseret kommunikationsprotokol. Her kan du " "aktivere og konfigurere din XMPP-server, kaldet ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client bruger med adgang til {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Chatserver" @@ -1994,14 +1987,14 @@ msgstr "" "vil se ud som brugernavn@%(domainname)s. Du kan konfigurere systemets " "domæne på Konfigurer siden." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2009,7 +2002,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2019,13 +2012,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2168,7 +2161,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2179,7 +2172,7 @@ msgstr "" "på din{box_name}. At holde en firewall aktiveret og velkonfigureret " "reducerer risikoen for sikkerhedstrusler fra internettet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall" @@ -2199,52 +2192,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port {name} ({details}) er ikke tilgængelig for eksterne netværk" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Firewall-tjenesten er ikke aktiv. Vær venlig at starte den. Den er som " -"standard aktiveret på %(box_name)s. På Debian-baserede systemer (som " -"%(box_name)s er) kan den startes med kommandoen 'service firewalld start' " -"eller hvis systemet bruger systemd 'systemctl start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Tjeneste/Port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Aktiveret" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Deaktiveret" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Tilladt" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Tilladt (kun internt)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Tilladt (kun eksternt)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Blokeret" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2254,13 +2234,13 @@ msgstr "" "også blive åbnet i firewallen, og når du deaktiverer en tjeneste blokeres " "den igen." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Avanceret" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2313,7 +2293,7 @@ msgstr "Start Konfiguration" msgid "Setup Complete" msgstr "Konfiguration Færdig" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2331,7 +2311,7 @@ msgstr "" "klient til kommandolinjen eller med flere tilgængelige grafiske klienter. Og " "så kan du dele din kode med mennesker over hele kloden." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2339,79 +2319,79 @@ msgstr "" "For at lære med om hvordan du bruger Git kan du besøge Git-vejledningen." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Læse- og skriveadgang til Git-repositorier" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Simpel Git-hosting" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Ugyldig URL til repositorie." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository name." msgstr "Ugyldigt værtsnavn" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 #, fuzzy #| msgid "packages not found" msgid "Repository's owner name" msgstr "pakker ikke fundet" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Create User" msgid "Private repository" msgstr "Opret Bruger" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 #, fuzzy #| msgid "This service already exists" msgid "A repository with this name already exists." msgstr "Denne tjeneste eksisterer allerede" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Create User" msgid "Name of the repository" msgstr "Opret Bruger" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Default" msgid "Default branch" msgstr "Standard" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2466,25 +2446,25 @@ msgstr "Slet Wiki eller Blog %(name)s" msgid "Delete this repository permanently?" msgstr "Slet bruger permanent?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 #, fuzzy #| msgid "packages not found" msgid "Repository created." msgstr "pakker ikke fundet" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 #, fuzzy #| msgid "An error occurred during configuration." msgid "An error occurred while creating the repository." msgstr "Der opstod en fejl under konfigurationen." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 #, fuzzy #| msgid "packages not found" msgid "Repository edited." msgstr "pakker ikke fundet" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 #, fuzzy #| msgid "Create User" msgid "Edit repository" @@ -2829,7 +2809,7 @@ msgstr "Om {box_name}" msgid "{box_name} Manual" msgstr "{box_name} Brugervejledning" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2837,7 +2817,7 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 #, fuzzy #| msgid "" #| "For more information about the %(box_name)s project, see the %(box_name)s Wiki-siden." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 #, fuzzy #| msgid "Enable application" msgid "Manage I2P application" msgstr "Aktiver applikation" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 #, fuzzy #| msgid "Tor Anonymity Network" msgid "Anonymity Network" msgstr "Tor Anonymiseringstjeneste" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2908,7 +2888,7 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 #, fuzzy #| msgid "" #| "ikiwiki is a simple wiki and blog application. It supports several " @@ -2925,7 +2905,7 @@ msgstr "" "kommentarer og RSS-feeds. Når aktiveret, vil blogge og wikier være " "tilgængelige på /ikiwiki." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2934,17 +2914,17 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 #, fuzzy #| msgid "Wiki & Blog" msgid "Wiki and Blog" msgstr "Wiki & Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 #, fuzzy #| msgid "Services and Applications" msgid "View and edit wiki applications" @@ -3002,43 +2982,43 @@ msgstr "" "Denne handling fjerner alle artikler, sider og kommentater inklusiv al " "historik. Slet denne wiki eller blog permanent?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Wiki {name} oprettet." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Kunne ikke oprette wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Blog {name} oprettet." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Kunne ikke oprette blog: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, fuzzy, python-brace-format #| msgid "{name} deleted." msgid "{title} deleted." msgstr "{name} slettet." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, fuzzy, python-brace-format #| msgid "Could not delete {name}: {error}" msgid "Could not delete {title}: {error}" msgstr "Kunne ikke slette {name}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3046,11 +3026,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 #, fuzzy #| msgid "Web Server" msgid "Gobby Server" @@ -3098,7 +3078,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -3118,7 +3098,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "IRC-klient (Quassel)" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "A digital certficate allows users of a web service to verify the identity " @@ -3139,7 +3119,7 @@ msgstr "" "Dette gøres ved at bekræfte overfor Let's Encrypt, en certifikat-autoritet " "(CA), at den har ejerskab over domænet." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 #, fuzzy #| msgid "" #| "Let's Encrypt is a free, automated, and open certificate authority, run " @@ -3159,17 +3139,17 @@ msgstr "" "org/repository/\">Let's Encrypts abonnementsbetingelser inden tjenesten " "tages i anvendelse." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 #, fuzzy #| msgid "Certificate Status" msgid "Certificates" msgstr "Certifikat Status" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3240,7 +3220,7 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, fuzzy, python-brace-format #| msgid "Certificate successfully revoked for domain {domain}" msgid "" @@ -3248,37 +3228,37 @@ msgid "" "moments to take effect." msgstr "Certifikatet for domænet {domain} blev trukket tilbage" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Fejl ved tilbagetrækning af certifikatet for domænet {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Certifikatet for domænet {domain} blev erhvervet" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" "Fejl ved forsøg på at erhverve certifikatet for domænet {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, fuzzy, python-brace-format #| msgid "Certificate successfully revoked for domain {domain}" msgid "Certificate successfully deleted for domain {domain}" msgstr "Certifikatet for domænet {domain} blev trukket tilbage" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, fuzzy, python-brace-format #| msgid "Failed to revoke certificate for domain {domain}: {error}" msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Fejl ved tilbagetrækning af certifikatet for domænet {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3288,14 +3268,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3385,7 +3365,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3393,7 +3373,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3402,18 +3382,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3494,49 +3474,49 @@ msgstr "Kodeord" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 #, fuzzy #| msgid "Application enabled" msgid "Public registrations enabled" msgstr "Applikation aktiveret" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 #, fuzzy #| msgid "Application disabled" msgid "Public registrations disabled" msgstr "Applikation deaktiveret" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 #, fuzzy #| msgid "PageKite enabled" msgid "Private mode enabled" msgstr "PageKite aktiveret" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 #, fuzzy #| msgid "PageKite disabled" msgid "Private mode disabled" msgstr "PageKite deaktiveret" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 #, fuzzy #| msgid "Setting unchanged" msgid "Default skin changed" msgstr "Indstilling uændret" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "Domænenavn gemt" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "Domænenavn gemt" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3549,11 +3529,11 @@ msgstr "" "For at forbinde til serveren skal der bruges en Minetest klient." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 #, fuzzy #| msgid "Block Sandbox (Minetest)" msgid "Block Sandbox" @@ -3606,7 +3586,7 @@ msgstr "" msgid "Address" msgstr "Adresse" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3793,19 +3773,19 @@ msgstr "Secure Shell" msgid "Services" msgstr "Tjeneste" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Netværk" @@ -4190,7 +4170,7 @@ msgstr "Rediger Forbindelse" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Rediger" @@ -4295,7 +4275,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Metode" @@ -4311,7 +4291,7 @@ msgstr "DNS-server" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Standard" @@ -4324,7 +4304,7 @@ msgid "This connection is not active." msgstr "Denne forbindelse er ikke aktiv." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Sikkerhed" @@ -4922,7 +4902,7 @@ msgstr "Slettede forbindelse {name}." msgid "Failed to delete connection: Connection not found." msgstr "Kunne ikke slette forbindelse: Forbindelse ikke fundet." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4939,26 +4919,26 @@ msgstr "" "af {box_name}. Du kan også tilgå resten af internettet igennem {box_name} " "for øget sikkerhed og anonymitet." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection Type" msgid "Connect to VPN services" msgstr "Forbindelsestype" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 #, fuzzy #| msgid "OpenVPN" msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 #, fuzzy #| msgid "Virtual Private Network (OpenVPN)" msgid "Virtual Private Network" msgstr "Virtuelt Privat Netværk (OpenVPN)" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4968,45 +4948,11 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -#, fuzzy -#| msgid "Mode" -msgid "Migrate" -msgstr "Tilstand" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, fuzzy, python-format #| msgid "" #| "To connect to %(box_name)s's VPN, you need to download a profile and feed " @@ -5017,8 +4963,8 @@ msgstr "Profil" #| "how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "For at forbinde til %(box_name)ss VPN skal du downloade en profil og " @@ -5028,18 +4974,19 @@ msgstr "" "Brugervejledning - OpenVPN\">dokumentation om anbefalede klienter og " "instruktioner til opsætning af dem." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Profilen er dannet specifikt til hver bruger af %(box_name)s. Hold den " "hemmelig." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Hent min profil" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5052,19 +4999,19 @@ msgstr "" "hvis {box_name} tjenester ikke kan nås fra resten af internettet. Dette " "inkluderer de følgende situationer:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} er bag en restriktiv firewall." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} er forbundet til en (trådløs) router som du ikke selv " "kontrollerer." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5072,7 +5019,7 @@ msgstr "" "Din internetudbyder tildeler dig ikke en ekstern IP-adresse, men giver dig " "forbindelse gennem NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 #, fuzzy #| msgid "" #| "Your ISP does not provide you a static IP address and your IP address " @@ -5084,11 +5031,11 @@ msgstr "" "Din internetudbyder tildeler dig ikke en fast IP-adresse, og din IP-adresse " "ændres hver gang du fobinder til nettet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Din internetudbyder begrænser indgående forbindelser." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, fuzzy, python-brace-format #| msgid "" #| "PageKite works around NAT, firewalls and IP-address limitations by using " @@ -5108,29 +5055,29 @@ msgstr "" "net. I fremtiden vil det måske blive muligt at bruge din vens {box_name} " "til dette." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 #, fuzzy #| msgid "Pagekite" msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 #, fuzzy #| msgid "Public Visibility (PageKite)" msgid "Public Visibility" msgstr "Offentlig Tilgængelighed (PageKite)" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 #, fuzzy #| msgid "PageKite Account" msgid "PageKite Domain" msgstr "PageKite-konto" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Serverdomæne" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5138,31 +5085,31 @@ msgstr "" "Vælg din PageKite-server. Brug \"pagekite.net\" hvis du vil bruge " "standardserveren fra pagekite.net." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Serverport" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "PageKite-serverport (standard: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite-navn" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Eksempel: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Ugyldigt kite-name" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite-hemmelighed" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5170,27 +5117,27 @@ msgstr "" "En hemmelighed tilknyttet denne kite, eller standard-hemmeligheden for din " "konto hvis der ikke er defineret nogen for denne kite." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protokol" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "ekstern (WAN) port" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "intern (FreedomBox) port" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Aktiver Subdomæner" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Brugerdefineret tjeneste slettet" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 #, fuzzy #| msgid "" #| "This service is available as a standard service. Please use the " @@ -5200,11 +5147,11 @@ msgstr "" "Denne tjeneste er tilgængelig som en standardtjeneste. Brug venligst siden " "\"Standardtjenester\" for at aktivere den." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Tilføjet brugerdefineret tjeneste" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Denne tjeneste eksisterer allerede" @@ -5246,29 +5193,29 @@ msgstr "" "her. For eksempel er HTTPS på andre porte end 443 kendt for at give " "problemer." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Webserver (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Siden vil være tilgængelig på http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Webserver (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Siden vil være tilgængelig på https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5314,8 +5261,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 #, fuzzy #| msgid "Restart Now" msgid "Restart" @@ -5365,6 +5312,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Sluk Nu" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Enable Privoxy" +msgid "Privacy" +msgstr "Aktiver Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5415,7 +5395,7 @@ msgstr "Privoxy Webproxy" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Tilgå {url} med proxy {proxy} ved brug af tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5432,7 +5412,7 @@ msgstr "" "kontinuerligt online, og du vil kunne bruge en eller flere Quassel-klienter " "fra en computer eller en mobil til at forbinde til den." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your computer og mobile enhed er tilgængelige." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 #, fuzzy #| msgid "Quassel IRC Client" msgid "IRC Client" @@ -5458,7 +5438,7 @@ msgstr "Quassel IRC-klient" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5479,19 +5459,19 @@ msgstr "" "carddav-clients\">understøttet klient-applikation. Radicale kan tilgås " "af enhver bruger der har et log ind til {box_name}." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 #, fuzzy #| msgid "Calendar and Addressbook (Radicale)" msgid "Calendar and Addressbook" @@ -5554,7 +5534,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 #, fuzzy #| msgid "Configuration updated" msgid "Access rights configuration updated" @@ -5653,7 +5633,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5668,13 +5648,13 @@ msgstr "Bro" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5683,31 +5663,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 #, fuzzy #| msgid "Network Time Server" msgid "Network File Storage" @@ -5795,17 +5775,17 @@ msgstr "Kite-navn" msgid "Action" msgstr "Handlinger" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS disk" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 #, fuzzy #| msgid "Add Service" msgid "Open Share" msgstr "Tilføj Service" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 #, fuzzy #| msgid "Add Service" msgid "Group Share" @@ -5841,57 +5821,57 @@ msgstr "{name} slettet." msgid "Error disabling share: {error_message}" msgstr "Kunne ikke installere applikation: {error}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 #, fuzzy #| msgid "Web Server" msgid "Web Search" msgstr "Webserver" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 #, fuzzy #| msgid "Save Services" msgid "Safe Search" msgstr "Gem Tjenester" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 #, fuzzy #| msgid "Mode" msgid "Moderate" msgstr "Tilstand" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -6073,14 +6053,14 @@ msgstr "Bogmærker (Shaarli)" msgid "Shaarlier" msgstr "Shaarli" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6089,107 +6069,107 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 #, fuzzy #| msgid "Service" msgid "Server" msgstr "Tjeneste" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 #, fuzzy #| msgid "Server port" msgid "Server port number" msgstr "Serverport" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 #, fuzzy #| msgid "Enable Shaarli" msgid "Sharing" msgstr "Aktiver Shaarli" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 #, fuzzy #| msgid "Publish Key" msgid "Public share" msgstr "Distribuer Nøgle" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 #, fuzzy #| msgid "This service already exists" msgid "A share with this name already exists." msgstr "Denne tjeneste eksisterer allerede" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -6232,30 +6212,30 @@ msgstr "" msgid "Add Share" msgstr "Tilføj Service" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 #, fuzzy #| msgid "Edit User" msgid "Edit Share" msgstr "Rediger Bruger" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 #, fuzzy #| msgid "{name} deleted." msgid "Share deleted." msgstr "{name} slettet." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6263,14 +6243,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 #, fuzzy #| msgid "Create User" msgid "Storage Snapshots" @@ -6378,7 +6358,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 #, fuzzy #| msgid "Delete %(name)s" msgid "Delete Snapshots" @@ -6430,65 +6410,65 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Library created." msgid "manually created" msgstr "Samling oprettet." -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 #, fuzzy #| msgid "Create User" msgid "Manage Snapshots" msgstr "Opret Bruger" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 #, fuzzy #| msgid "Configuration updated" msgid "Storage snapshots configuration updated" msgstr "Konfiguration opdateret" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Fejl under handling: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 #, fuzzy #| msgid "Delete %(name)s" msgid "Deleted selected snapshots" msgstr "Slet %(name)s" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6496,7 +6476,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Secure Shell (SSH) Server" @@ -6535,14 +6515,6 @@ msgstr "" msgid "Fingerprint" msgstr "SSH-fingeraftryk" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -6557,7 +6529,7 @@ msgstr "Log ind" msgid "Logged out successfully." msgstr "Kodeord blev ændret." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6565,164 +6537,164 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 #, fuzzy #| msgid "reStore" msgid "Storage" msgstr "reStore" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, fuzzy, python-brace-format #| msgid "{disk_size} bytes" msgid "{disk_size:.1f} bytes" msgstr "{disk_size} bytes" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, fuzzy, python-brace-format #| msgid "{disk_size} KiB" msgid "{disk_size:.1f} KiB" msgstr "{disk_size} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, fuzzy, python-brace-format #| msgid "{disk_size} MiB" msgid "{disk_size:.1f} MiB" msgstr "{disk_size} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, fuzzy, python-brace-format #| msgid "{disk_size} GiB" msgid "{disk_size:.1f} GiB" msgstr "{disk_size} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, fuzzy, python-brace-format #| msgid "{disk_size} TiB" msgid "{disk_size:.1f} TiB" msgstr "{disk_size} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 #, fuzzy #| msgid "repro service is running" msgid "The device is already unmounting." msgstr "repro-tjenesten er aktiv" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 #, fuzzy #| msgid "This service already exists" msgid "The device is already mounted." msgstr "Denne tjeneste eksisterer allerede" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 #, fuzzy #| msgid "repro service is not running" msgid "The device is not mounted." msgstr "repro-tjenesten er ikke aktiv" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid directory name." msgstr "Ugyldigt værtsnavn" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 #, fuzzy #| msgid "Download directory" msgid "Path is not a directory." msgstr "Download-mappe" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 #, fuzzy #| msgid "Download directory" msgid "Directory" msgstr "Download-mappe" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 #, fuzzy #| msgid "Add Service" msgid "Share" msgstr "Tilføj Service" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6761,7 +6733,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Udvid Rod-partition" @@ -6782,30 +6754,30 @@ msgstr "" "Efter denne operation, vil der være yderligere %(expandable_root_size)s fri " "diskplads på din rod-partition." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Kunne ikke udvidde partition: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Partition blev udviddet." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6813,7 +6785,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6825,22 +6797,22 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 #, fuzzy #| msgid "Install this application?" msgid "Administer Syncthing application" msgstr "Installer denne applikation?" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6854,7 +6826,7 @@ msgstr "" "du bruger Tor-browseren." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, fuzzy, python-brace-format #| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." msgid "" @@ -6862,42 +6834,42 @@ msgid "" "TCP port 9050." msgstr "En Tor SOCKS-port er tilgængelig på din %(box_name)s TCP-port 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 #, fuzzy #| msgid "Tor Hidden Service" msgid "Tor Onion Service" msgstr "Tor Skjult Tjeneste" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor Bridge Relay" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor videresendelsesport tilgængelig" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 transport registreret" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 transport registreret" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Tilgå URL {url} ved brug af tcp{kind} via Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bekræft brug af Tor på {url} ved brug af tcp{kind}" @@ -7010,13 +6982,13 @@ msgstr "Skjult Tjeneste" msgid "Ports" msgstr "Porte" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Der opstod en fejl under konfigurationen." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -7079,7 +7051,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission BitTorrent" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7089,7 +7061,7 @@ msgstr "" "er designet til at læse nyheder på farten, men samtidig føles så meget som " "en rigtig desktop-applikation som muligt." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Tiny Tiny RSS will be available from /" @@ -7101,17 +7073,17 @@ msgstr "" "Når aktiveret, vil Tiny Tiny RSS være tilgængelige på stien /tt-rss på webserveren." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 #, fuzzy #| msgid "News Feed Reader (Tiny Tiny RSS)" msgid "News Feed Reader" @@ -7121,12 +7093,12 @@ msgstr "Nyhedsstrømlæser (Tiny Tiny RSS)" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7134,8 +7106,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -7143,30 +7115,30 @@ msgstr "" msgid "Software Update" msgstr "Softwareopdateringer" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox Manual" msgid "FreedomBox Updated" msgstr "FreedomBox Brugervejledning" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution update started" msgstr "Automatisk opdatering deaktiveret" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7352,58 +7324,58 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Automatisk opdatering aktiveret" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" "Kunne ikke konfigurere automatisk opdatering (unattended-upgrades): {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Automatisk opdatering aktiveret" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Automatisk opdatering deaktiveret" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Distribution upgrade enabled" msgstr "Automatisk opdatering aktiveret" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution upgrade disabled" msgstr "Automatisk opdatering deaktiveret" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Opdateringsprocessen er startet." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Kunne ikke starte opdatering." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Starting distribution upgrade test." msgstr "Automatisk opdatering aktiveret" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7411,15 +7383,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Brugere og Grupper" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Kontrol af LDAP-konfiguration \"{search_item}\"" @@ -7439,25 +7411,25 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 #, fuzzy #| msgid "Administrator Account" msgid "Authorization Password" msgstr "Administratorkonto" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Show password" msgid "Invalid password." msgstr "Vis kodeord" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 #, fuzzy #| msgid "" #| "Select which services should be available to the new user. The user will " @@ -7479,13 +7451,13 @@ msgstr "" "tjenester. De kan også logge ind på systemet gennem SSH og har " "administratorprivilegier (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "Kunne ikke oprette LDAP-bruger." -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" @@ -7505,46 +7477,46 @@ msgstr "" "sikkert ind på systemet uden et kodeord. Der kan defineres flere nøgler, en " "på hver linje. Tomme linjer og linjer som starter med # bliver ignoreret." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Kunne ikke omdøbe LDAP-bruger." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Kunne ikke fjerne bruger fra gruppe." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Kunne ikke tilføje bruger til gruppe." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "Kunne ikke tilføje bruger til gruppe." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Kunne ikke ændre LDAP-kodeord." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "Kunne ikke tilføje ny bruger til admin-gruppen." -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, fuzzy, python-brace-format #| msgid "Failed to obtain certificate for domain {domain}: {error}" msgid "Failed to restrict console access: {error}" msgstr "" "Fejl ved forsøg på at erhverve certifikatet for domænet {domain}: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Brugerkonto oprettet, du er nu logget ind" @@ -7561,12 +7533,12 @@ msgstr "Gem Kodeord" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Opret Bruger" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Slet Bruger" @@ -7611,17 +7583,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Brugere" @@ -7654,34 +7626,34 @@ msgstr "" msgid "Save Changes" msgstr "Gem Ændringer" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Bruger %(username)s oprettet." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Bruger %(username)s opdateret." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Rediger Bruger" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Brugeren {user} slettet." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Kunne ikke slette LDAP-bruger." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Ændr kodeord" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Kodeord blev ændret." @@ -8042,7 +8014,7 @@ msgstr "Slet Forbindelse" msgid "Server deleted." msgstr "{name} slettet." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8051,7 +8023,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8060,28 +8032,28 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 #, fuzzy #| msgid "Address" msgid "WordPress" msgstr "Adresse" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Wiki & Blog" msgid "Website and Blog" @@ -8099,7 +8071,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8112,7 +8084,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8120,11 +8092,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -8177,114 +8149,108 @@ msgstr "" msgid "Finished: {name}" msgstr "Tjeneste ikke aktiv: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing Backups" -msgid "Error running apt-get" -msgstr "Eksisterende sikkerhedskopier" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "Installerer" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "downloader" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "medie-ændring" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "konfigurationsfil: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Installer applikationer" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Kunne ikke installere applikation: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Kunne ikke installere applikation: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Kunne ikke installere applikation: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Kunne ikke installere applikation: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Applikation installeret." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Seneste opdatering" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Installer applikationer" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Kunne ikke installere applikation: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Kunne ikke installere applikation: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Applikation installeret." -#: plinth/setup.py:451 +#: plinth/setup.py:452 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8353,58 +8319,58 @@ msgstr "Installation" msgid "Service %(service_name)s is not running." msgstr "Tjenestesøgningstjenesten er ikke aktiv" -#: plinth/templates/base.html:30 -#, fuzzy, python-format -#| msgid "Plinth administrative interface for the %(box_name)s" -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Plinth administrationsværktøj til %(box_name)s" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Apps" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Apps" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " System" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "System" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Ændr kodeord" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 #, fuzzy #| msgid "Shut Down Now" msgid "Shut down" msgstr "Sluk Nu" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Log ud" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 #, fuzzy #| msgid "Language" msgid "Select language" msgstr "Sprog" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Log ind" @@ -8687,6 +8653,39 @@ msgstr "" msgid "Gujarati" msgstr "" +#~ msgid "Enable DNSSEC" +#~ msgstr "Aktivér DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Akiver sikkerhedsudvidelser til DNS (DNSSEC)" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Firewall-tjenesten er ikke aktiv. Vær venlig at starte den. Den er som " +#~ "standard aktiveret på %(box_name)s. På Debian-baserede systemer (som " +#~ "%(box_name)s er) kan den startes med kommandoen 'service firewalld start' " +#~ "eller hvis systemet bruger systemd 'systemctl start firewalld'." + +#, fuzzy +#~| msgid "Mode" +#~ msgid "Migrate" +#~ msgstr "Tilstand" + +#, fuzzy +#~| msgid "Existing Backups" +#~ msgid "Error running apt-get" +#~ msgstr "Eksisterende sikkerhedskopier" + +#, fuzzy, python-format +#~| msgid "Plinth administrative interface for the %(box_name)s" +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Plinth administrationsværktøj til %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Netværksforbindelser" diff --git a/plinth/locale/de/LC_MESSAGES/django.po b/plinth/locale/de/LC_MESSAGES/django.po index 465475334..ba3bc854c 100644 --- a/plinth/locale/de/LC_MESSAGES/django.po +++ b/plinth/locale/de/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: German calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1062,23 +1055,23 @@ msgstr "" "Nur Benutzer der calibre Gruppe können auf die App zugreifen. Alle " "Benutzer mit Zugangsberechtigung können alle Bibliotheken nutzen." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Verwenden von Calibre-E-Book-Bibliotheken" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "E-Book-Bibliothek" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Name der neuen Bibliothek" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1086,7 +1079,7 @@ msgstr "" "Nur Buchstaben des englischen Alphabets, Zahlen und die Zeichen _ . und - " "ohne Leerzeichen oder Sonderzeichen. Beispiel: Meine_Bibliothek_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Eine Bibliothek mit diesem Namen ist bereits vorhanden." @@ -1134,20 +1127,20 @@ msgstr "Gehe zur Bibliothek %(library)s" msgid "Delete library %(library)s" msgstr "Bibliothek löschen %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Bibliothek erstellt." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Beim Erstellen der Bibliothek ist ein Fehler aufgetreten." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} gelöscht." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "{name} konnte nicht gelöscht werden: {error}" @@ -1197,7 +1190,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Serververwaltung" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1205,18 +1198,18 @@ msgstr "" "Hier können Sie einige allgemeine Konfigurationsoptionen wie Hostname, " "Domainname, Webserver-Homepage usw. festlegen." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Allgemeine Konfiguration" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Konfigurieren" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1332,47 +1325,47 @@ msgstr "" "Die Protokolle enthalten Informationen darüber, wer auf das System " "zugegriffen hat, sowie Debug-Informationen von verschiedenen Diensten" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Fehler beim Setzen des Hostnamens: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Hostname gesetzt" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Fehler beim Setzen des Domainnamens: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Domainname gesetzt" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Fehler beim Setzen des Host-Namen: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Webserver-Startseite wurde definiert" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Fehler beim Ändern des erweiterten Modus: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Zeige erweiterte Anwendungen und Funktionen an" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Ausblenden von erweiterten Apps und Funktionen" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1385,7 +1378,7 @@ msgstr "" "verwenden, um eine Verbindung zwischen Parteien herzustellen, die sich sonst " "nicht miteinander verbinden können." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ejabberd müssen mit den hier angegebenen Details " "konfiguriert werden." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP-Helfer" @@ -1460,11 +1453,11 @@ msgstr "Fehler beim Setzen der Zeitzone: {exception}" msgid "Time zone set" msgstr "Zeitzone gesetzt" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge ist ein BitTorrent-Client mit einer Weboberfläche." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1472,16 +1465,16 @@ msgstr "" "Das Standardkennwort ist 'deluge'; Sie sollten sich aber anmelden und es " "sofort ändern, nachdem Sie diesen Dienst aktiviert haben." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Dateien mit BitTorrent herunterladen" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent-Webclient" @@ -1609,7 +1602,7 @@ msgstr "Ergebnis" msgid "Diagnostic Test" msgstr "Diagnose" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1621,7 +1614,7 @@ msgstr "" "zu finden. Dadurch werden andere daran gehindert, jene Dienste zu finden, " "die von Ihrer {box_name} angeboten werden." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1639,7 +1632,7 @@ msgstr "" "neuen IP zuweisen, und wenn jemand aus dem Internet nach Ihrem DNS-Namen " "fragt, erhält er eine Antwort mit Ihrer aktuellen IP-Adresse." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1652,11 +1645,11 @@ msgstr "" "freedns.afraid.org/\" target=\"_blank\">freedns.afraid.org können " "mittels Update-URL genutzt werden." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Dynamischer DNS-Client" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Dynamischer Domain-Name" @@ -1787,7 +1780,7 @@ msgstr "Dieses Feld ist erforderlich." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1842,7 +1835,7 @@ msgstr "Server verweigert Verbindung" msgid "Already up-to-date" msgstr "Bereits auf dem neuesten Stand" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1850,7 +1843,7 @@ msgstr "" "XMPP ist ein offenes und standardisiertes Kommunikationsprotokoll. Hier " "können Sie Ihren XMPP-Server, genannt ejabberd, starten und konfigurieren." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client Benutzer mit " "einem {box_name} Login aufgerufen werden." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn-App oder konfiguriere einen externen " "Server." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Chatserver" @@ -2005,7 +1998,7 @@ msgstr "" "auf der Seite Systemeinstellungen " "konfigurieren." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -2016,7 +2009,7 @@ msgstr "" "Mail-Clients den Zugriff auf Ihre Mailbox über IMAP und POP3. Rspamd kümmert " "sich um Spam." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2029,7 +2022,7 @@ msgstr "" "ausdrücklichen Wunsch auf. Weitere Informationen finden Sie auf der " "Handbuchseite." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2044,7 +2037,7 @@ msgstr "" "Adresse Aliasnamen hinzufügen. Notwendige Aliase wie \"postmaster\" werden " "automatisch erstellt und verweisen auf den ersten Admin-Benutzer." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2052,7 +2045,7 @@ msgstr "" "Roundcube App bietet eine " "Weboberfläche für den Zugriff auf E-Mails." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2183,7 +2176,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "Host/Ziel/Wert" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2194,7 +2187,7 @@ msgstr "" "Verkehr Ihrer {box_name} kontrolliert. Die Firewall aktiv und korrekt " "konfiguriert halten reduziert Sicherheitsrisiken aus dem Internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall" @@ -2214,52 +2207,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port -Name {name} ({details}) für externe Netzwerke nicht verfügbar" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Firewalldaemon läuft nicht. Bitte starten. Die Firewall ist standardmäßig " -"auf %(box_name)s aktiviert. Auf jedem Debian-basierten System (wie " -"%(box_name)s) kann sie über das Kommando „service firewalld start“ oder bei " -"einem System mit systemd mit „systemctl start firewalld“ gestartet werden." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Dienst/Port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Aktiviert" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Deaktiviert" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Erlaubt" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Erlaubt (nur intern)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Erlaubt (nur extern)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Geblockt" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2269,13 +2249,13 @@ msgstr "" "aktivieren, wird dieser in der Firewall ebenfalls aktiviert und wenn Sie " "einen Dienst deaktivieren, wird dieser ebenso in der Firewall deaktiviert." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Fortgeschritten" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2331,7 +2311,7 @@ msgstr "Einrichten beginnen" msgid "Setup Complete" msgstr "Installation abgeschlossen" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2350,7 +2330,7 @@ msgstr "" "Git-Befehlszeilenclient oder mit mehreren verfügbaren Grafikclients " "hochladen. Und Sie können Ihren Code mit Menschen auf der ganzen Welt teilen." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2358,71 +2338,71 @@ msgstr "" "Um weiter über Git Betrieb zu lernen, schauen Sie sich die Gitanleitung an." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Lese- und Schreibberechtigung auf Git respositories" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Einfaches Git Hosting" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Ungültige Repository-URL." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Ungültiger Respositoryname." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Name eines neuen Repositorys oder einer neuen URL zum Importieren eines " "vorhandenen Repositorys." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Beschreibung des Archivs" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Optional, zur Anzeige auf Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Name des Resposity Besitzers" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Privates Archiv" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Zugriff auf diesem Repository nur bevollmächtigte Benutzer erlauben." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Eine Archiv mit diesem Namen existiert bereits." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Name des resositorys" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" "Eine alphanumerische Zeichenfolge, die ein Repository eindeutig " "identifiziert." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Standard Thema" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb zeigt dies als Standard-Zweig an." @@ -2466,19 +2446,19 @@ msgstr "Git Repository %(name)s löschen" msgid "Delete this repository permanently?" msgstr "Dieses respository permanent löschen?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Archiv erstellt." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Beim Erstellen des Repository ist ein Fehler aufgetreten." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Archiv bearbeitet." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Archiv bearbeiten" @@ -2846,7 +2826,7 @@ msgstr "Über Ihre FreedomBox {box_name}" msgid "{box_name} Manual" msgstr "{box_name}-Handbuch" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2858,7 +2838,7 @@ msgstr "" "Anonymität, indem es verschlüsselten Datenverkehr über ein von Freiwilligen " "betriebenes, weltweit verteiltes Netzwerk sendet." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2866,7 +2846,7 @@ msgstr "" "Mehr Informationen über I2P finden Sie auf deren Projekt-Webseite." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2874,19 +2854,19 @@ msgstr "" "Der erste Besuch der bereitgestellten Weboberfläche leitet den " "Konfigurationsprozess ein." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "I2P-Anwendung verwalten" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Anonymisierungsnetzwerk" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2932,7 +2912,7 @@ msgstr "" "einem Peer-to-Peer-Netzwerk. Laden Sie Dateien herunter, indem Sie Torrents " "hinzufügen, oder erstellen Sie einen neuen Torrent, um eine Datei zu teilen." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2942,7 +2922,7 @@ msgstr "" "einfache Markup-Sprachen, einschließlich Markdown, und gängige Blogging-" "Funktionalität wie Kommentare und RSS-Feeds." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2956,15 +2936,15 @@ msgstr "" "\"{users_url}\">Benutzerkonfiguration können diese Rechte geändert oder " "neue Benutzer angelegt werden." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki und Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Wiki-Anwendungen ansehen und bearbeiten" @@ -3020,41 +3000,41 @@ msgstr "" "Diese Aktion wird alle Posts, Seiten und Kommentare einschließlich der " "Historie löschen. Dieses Wiki oder den Blog dauerhaft löschen?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Wiki {name} angelegt." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Wiki konnte nicht angelegt werden: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Blog {name} angelegt." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Blog konnte nicht angelegt werden: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} gelöscht." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "{title} konnte nicht gelöscht werden: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted ist ein Server für Gobby, den kollaborativen Text-Editor." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3065,11 +3045,11 @@ msgstr "" "Client herunterladen und installieren. Dann Gobby starten und „Mit " "Server verbinden“ auswählen und den Domainnamen Ihrer {box_name} eingeben." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby-Server" @@ -3119,7 +3099,7 @@ msgstr "Janus-Videoraum" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "JavaScript-Lizenzinformation" @@ -3139,7 +3119,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Chatclient" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3155,7 +3135,7 @@ msgstr "" "Zertifizierungsstelle Let's Encrypt nachweist, der Inhaber einer Domain zu " "sein." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3169,15 +3149,15 @@ msgstr "" "akzeptieren Sie die Let's " "Encrypt Vetragsvereinbarungen vor der Verwendung dieses Dienstes." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Zertifikate" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Kann nicht testen: Es sind keine Domains konfiguriert." @@ -3242,7 +3222,7 @@ msgstr "" "Es wurden keine Domains konfiguriert. Um Zertifikate erhalten zu können, " "müssen Domains konfiguriert werden." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3251,34 +3231,34 @@ msgstr "" "Zertifikat erfolgreich widerrufen für Domain {domain}. Es kann einige " "Momente dauern, bis dies in Kraft tritt." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Fehler beim Widerrufen des Zertifikats für Domain {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Zertifikat erfolgreich bezogen für Domain {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Fehler beim Beziehen des Zertifikats für Domain {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Zertifikat erfolgreich widerrufen für Domain {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Fehler beim Widerrufen des Zertifikats für Domain {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3296,7 +3276,7 @@ msgstr "" "einem bestimmten Matrix Server können dank Föderation zwischen den Servern " "mit Nutzerkonten auf einem beliebigen anderen Server kommunizieren." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3306,7 +3286,7 @@ msgstr "" "Installiere die Coturn-App oder konfiguriere " "einen externen Server." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3414,7 +3394,7 @@ msgstr "" "Zertifikat. Bitte gehen Sie zu Let's " "Encrypt, um eines zu beziehen." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3427,7 +3407,7 @@ msgstr "" "nutzen, um eine Wiki-Webseite anzubieten, um Notizen zu schreiben oder um " "mit Freunden an einem Projekt zusammen zu arbeiten." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3442,7 +3422,7 @@ msgstr "" "Seite Spezial: Konto-" "Erstellen nutzen." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3450,12 +3430,12 @@ msgstr "" "Alle mit einem Link zu diesem Wiki können es lesen. Ausschließlich " "angemeldete Nutzer können den Inhalt verändern." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3540,35 +3520,35 @@ msgstr "" "Kennwortaktualisierung fehlgeschlagen. Bitte wählen Sie ein stärkeres " "Passwort" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Öffentliche Registrierung aktiviert" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Öffentliche Registrierung deaktiviert" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Privater Modus aktiviert" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Privater Modus ausgeschaltet" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Standard-Thema geändert" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Domainname aktualisiert" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Website-Name aktualisiert" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3581,11 +3561,11 @@ msgstr "" "Standardport (30000). Um auf dem Server zu spielen, wird ein Minetest-Client benötigt." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Block-Sandkasten" @@ -3638,7 +3618,7 @@ msgstr "" msgid "Address" msgstr "Adresse" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3826,7 +3806,7 @@ msgstr "Secure Shell" msgid "Services" msgstr "Dienste" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3835,7 +3815,7 @@ msgstr "" "eine Verbindung zum Internet her. Teilen Sie diese Verbindung mit anderen " "Geräten im Netzwerk." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3843,7 +3823,7 @@ msgstr "" "Geräte die mit anderen Methoden verwaltet werden, können hier möglicherweise " "nicht konfiguriert werden." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Netzwerke" @@ -4285,7 +4265,7 @@ msgstr "Verbindung bearbeiten" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Bearbeiten" @@ -4390,7 +4370,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Methode" @@ -4406,7 +4386,7 @@ msgstr "DNS-Server" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Standard" @@ -4419,7 +4399,7 @@ msgid "This connection is not active." msgstr "Diese Verbindung ist nicht aktiv." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Sicherheit" @@ -5012,7 +4992,7 @@ msgstr "Verbindung {name} gelöscht." msgid "Failed to delete connection: Connection not found." msgstr "Konnte Verbindung nicht löschen: Verbindung nicht gefunden." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -5029,20 +5009,20 @@ msgstr "" "{box_name} erlangen. Sie können auch auf das Internet via {box_name} für " "zusätzliche Sicherheit und Anonymität zugreifen." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Mit VPN-Diensten verbinden" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Virtuelles Privates Netzwerk" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5053,60 +5033,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" -"Migration zur ECC-Kryptographie (Kryptographie basierend auf elliptischen " -"Kurven)" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Ihre OpenVPN-Installation verwendet derzeit RSA. Der Umstieg auf die moderne " -"Elliptische-Kurven-Kryptographie verbessert die Geschwindigkeit des " -"Verbindungsaufbaus und die Sicherheit. Dieser Vorgang unumkehrbar. Sie " -"sollte auf den meisten Einplatinencomputern nur wenige Minuten dauern." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Alle neuen Installationen von OpenVPN auf %(box_name)s verwenden " -"standardmäßig ECC. Wir empfehlen, so bald wie möglich zu wechseln." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Warnung: Bestehende Client-Profile werden durch diese Operation " -"ungültig. Alle OpenVPN-Benutzer auf %(box_name)s müssen ihre neuen Profile " -"herunterladen. Für die Verbindung zu diesem Server sollten OpenVPN-Clients " -"verwendet werden, die mit ECC kompatibel sind." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Migrieren" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Um eine Verbindung mit dem VPN von %(box_name)s herzustellen, müssen Sie ein " @@ -5115,18 +5056,19 @@ msgstr "" "verfügbar. Klicken Sie auf \"Mehr erfahren...\" empfohlenen Clients und " "Anweisungen zur Konfiguration." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Das Profil ist für jeden Benutzer von %(box_name)s spezifisch. Halten Sie es " "geheim." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Mein Profil herunterladen" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5139,19 +5081,19 @@ msgstr "" "die Dienste Ihrer {box_name} vom Internet nicht erreichbar sind. Dies " "umfasst folgende Situationen:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} ist hinter einer eingeschränkten Firewall." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} ist mit einem (wireless)-Router verbunden, den Sie nicht " "kontrollieren." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5159,7 +5101,7 @@ msgstr "" "Ihr ISP bietet Ihnen keine externe IP-Adresse, sondern statt dessen eine " "Internetverbindung über NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5167,11 +5109,11 @@ msgstr "" "Ihr ISP bietet keine statische IP-Adresse und Ihre IP-Adresse ändert sich " "immer, wenn Sie sich mit dem Internet verbinden." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Ihr ISP schränkt eingehende Verbindungen ein." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5185,23 +5127,23 @@ msgstr "" "\"https://pagekite.net\">pagekite.net. In der Zukunft könnte es möglich " "sein, hierfür die {box_name} eines Freundes zu nutzen." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Öffentliche Sichtbarkeit" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite Domäne" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Serverdomain" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5209,31 +5151,31 @@ msgstr "" "Wählen Sie Ihren PageKite-Server aus. „pagekite.net“ festlegen, um den " "Standardserver zu verwenden." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Serverport" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Port Ihres PageKite-Servers (standard: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite-Name" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Beispiel: meinebox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Ungültiger kite-Name" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite secret" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5241,35 +5183,35 @@ msgstr "" "Ein secret assoziiert mit dem kite oder das Standard-secret für Ihr Konto, " "wenn kein secret dem kite zugeordnet ist." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "Protokoll" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "externer (frontend) Port" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "interner (FreedomBox) Port" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Sub-Domainen einschalten" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Spezieller Dienst gelöscht" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Dieser Service ist bereits als Standard-Service verfügbar." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Spezieller Dienst hinzugefügt" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Dieser Dienst existiert bereits" @@ -5307,31 +5249,31 @@ msgstr "" "Beispielsweise HTTPS auf anderen Ports als 443, ist bekannt dafür, Probleme " "zu verursachen." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Webserver (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" "Webseite wird unter http://{0} verfügbar sein" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Webserver (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" "Webseite wird unter https://{0} verfügbar sein" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5383,8 +5325,8 @@ msgstr "" "Derzeit läuft eine Installation oder Update. Überlegen Sie auf die " "Fertigstellung zu warten, bevor Sie herunterfahren oder neu starten." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Neu starten" @@ -5435,6 +5377,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Jetzt herunterfahren" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5476,7 +5451,7 @@ msgstr "Web Proxy" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Zugang auf {url} über Proxy {proxy} auf TCP{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5494,7 +5469,7 @@ msgstr "" "mobilen App können verwendet werden, um sich mit ihm zu verbinden und oder " "zu trennen." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your Desktop und mobile Telefone zur Verfügung." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC-Client" @@ -5518,7 +5493,7 @@ msgstr "IRC-Client" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5533,7 +5508,7 @@ msgstr "" "supported-clients\">unterstützte Client Software notwendig. Radicale " "kann von jedem Benutzer mit einem {box_name}-Konto verwendet werden." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5544,12 +5519,12 @@ msgstr "" "Kontaktdaten wird nicht unterstützt; dies muss über einen separaten Client " "erfolgen." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Kalender und Adressbuch" @@ -5623,7 +5598,7 @@ msgstr "" "freedombox.adresse>) und ihren Benutzernamen. Wenn Sie auf den Suchen-Knopf " "drücken, werden die bestehenden Kalender und Adressbücher aufgelistet." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Konfiguration der Zugangsrechte aktualisiert" @@ -5718,7 +5693,7 @@ msgstr "" "Hinzufügen eines Feeds die Authentifizierung und verwenden Sie Ihre " "{box_name}-Anmeldeinformationen." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Lesen und Abonnieren von Neuigkeiten-Feeds" @@ -5731,7 +5706,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "RSS Feed Generator" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5739,7 +5714,7 @@ msgstr "" "Samba ermöglicht das Teilen von Dateien und Ordnern zwischen der FreedomBox " "und anderen Rechnern im lokalen Netzwerk." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5753,11 +5728,11 @@ msgstr "" "Windows) oder smb://{hostname}.local (unter Linux und Mac) zugegriffen " "werden. Es gibt drei Arten von Shares, aus denen Sie wählen können: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Offene Freigabe - für alle in Ihrem lokalen Netzwerk zugänglich." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5765,7 +5740,7 @@ msgstr "" "Gruppenfreigabe - nur für FreedomBox-Benutzer zugänglich, die sich in der " "Freedombox-Freigabegruppe befinden." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5773,15 +5748,15 @@ msgstr "" "Home Share - jeder Benutzer in der freedombox-share-Gruppe kann seinen " "eigenen privaten Raum haben." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Zugriff auf die privaten Freigaben" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Netzwerkdateispeicherung" @@ -5869,15 +5844,15 @@ msgstr "Freigabename" msgid "Action" msgstr "Aktion" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS Datenträger" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Open Share" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Group Share" @@ -5903,7 +5878,7 @@ msgstr "Freigabe deaktiviert." msgid "Error disabling share: {error_message}" msgstr "Fehler beim Deaktivieren der Freigabe: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5911,7 +5886,7 @@ msgstr "" "Searx ist eine Internet-Metasuchmaschine, die die Privatsphäre respektiert. " "Sie sammelt und zeigt Ergebnisse von mehreren Suchmaschinen an." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5919,41 +5894,41 @@ msgstr "" "Searx kann verwendet werden, um Nachverfolgung und Profiling durch " "Suchmaschinen zu vermeiden. Standardmäßig werden keine Cookies gespeichert." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Suche im Web" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Websuche" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Sichere Suche" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Wählen Sie den standardmäßigen Familienfilter, der auf Ihre Suchergebnisse " "angewendet werden soll." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Moderat" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Streng" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Öffentlichen Zugang erlauben" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Erlauben, dass diese Anwendung von jedem verwendet werden kann, der sie " @@ -6135,7 +6110,7 @@ msgstr "Lesezeichen" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6145,7 +6120,7 @@ msgstr "" "Internetverkehr zu schützen. Er kann verwendet werden, um Internetfilterung " "und -zensur zu umgehen." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6158,7 +6133,7 @@ msgstr "" "betrieben. Lokale Geräte können sich mit diesem Proxy verbinden, und deren " "Daten werden verschlüsselt über den Shadowsocks-Server weitergeleitet." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6167,44 +6142,44 @@ msgstr "" "SOCKS5-Proxy in ihrem Gerät, Browser, oder Anwendung auf http://" "Freedombox_Adresse:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Socks5-Proxy" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Empfohlen" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Server" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Servername oder IP-Adresse" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Server-Portnummer" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Passwort, um Daten zu verschlüsseln. Muss mit dem Server-Passwort " "übereinstimmen." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" "Verschlüsselungsverfahren. Muss mit der Einstellung des Servers " "übereinstimmen." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6213,15 +6188,15 @@ msgstr "" "Sharing ermöglicht es Ihnen, Dateien und Ordner auf Ihrer {box_name} über " "das Internet mit ausgewählten Benutzergruppen zu teilen." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Sharing" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Name der Freigabe" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6229,30 +6204,30 @@ msgstr "" "Eine alphanumerische Zeichenfolge in Kleinbuchstaben, die eine Freigabe " "eindeutig identifiziert. Beispiel: media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Freizugebender Pfad" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" "Plattenpfad zu einem Ordner auf diesem Server, den Sie freigeben möchten." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Öffentlich freigeben" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" "Dateien in diesem Ordner jedem zur Verfügung stellen, der über den Link " "verfügt." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Benutzergruppen, die Dateien in der Freigabe lesen können:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6260,11 +6235,11 @@ msgstr "" "Benutzer der ausgewählten Benutzergruppen können die Dateien in der Freigabe " "lesen." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Eine Freigabe mit diesem Namen existiert bereits." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "Freigaben sollten öffentlich sein oder mindestens einer Gruppe haben" @@ -6301,19 +6276,19 @@ msgstr "Freigabe hinzugefügt." msgid "Add Share" msgstr "Freigabe hinzufügen" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Freigabe geändert." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Freigabe bearbeiten" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Freigabe gelöscht." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6324,7 +6299,7 @@ msgstr "" "unerwünschte Änderungen in einen vorherigen bekannten guten Zustand zurück " "zu versetzen." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6336,7 +6311,7 @@ msgstr "" "Software. Ältere Schnappschüsse werden gemäß den Einstellungen unten " "automatisch bereinigt." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for Datensicherungen, da sie nur auf derselben " "Partition gespeichert werden können. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Speicherauszüge" @@ -6451,7 +6426,7 @@ msgstr "Datum" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Speicherauszüge löschen" @@ -6505,60 +6480,60 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Zurücksetzen auf Speicherauszug #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "Manuell erstellt" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "Zeitleiste" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Schnappschüsse verwalten" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Schnappschuss erstellt." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Konfiguration der Speicherauszüge aktualisiert" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Aktionsfehler: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Ausgewählte Schnappschüsse gelöscht" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" "Schnappschüsse ist derzeit im Gebrauch. Bitte versuchen Sie es später noch " "einmal." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Zurückgesetzt auf Speicherauszug #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" "Das System muss neu gestartet werden, um das Zurücksetzen abzuschließen." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Zurücksetzen auf Speicherauszug" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6570,7 +6545,7 @@ msgstr "" "verifizierter, entfernter Computer Verwaltungsaufgaben ausführen, Dateien " "kopieren oder andere Anwendungen starten." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Secure Shell (SSH) Server" @@ -6609,14 +6584,6 @@ msgstr "Algorithmus" msgid "Fingerprint" msgstr "Fingerabdruck" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "SSH-Authentifizierung mit Passwort deaktiviert." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "SSH-Authentifizierung mit Passwort aktiviert." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Einmal-Anmeldung" @@ -6629,7 +6596,7 @@ msgstr "Anmelden" msgid "Logged out successfully." msgstr "Erfolgreich abgemeldet." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6641,109 +6608,109 @@ msgstr "" "Speichermedien einsehen, Wechselmedien einbinden und aushängen, die Root-" "Partition erweitern usw." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Speicher" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} Bytes" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Der Vorgang schlug fehl." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Der Vorgang wurde abgebrochen." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Das Gerät wird bereits ausgehängt." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" "Der Vorgang ist wegen fehlender Treiber-/Werkzeugunterstützung nicht möglich." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Der Vorgang beendet wegen Zeitüberschreitung." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" "Dieser Vorgang würde ein Gerät aufwecken, welches sich in einem Tiefschlaf-" "Zustand befindet." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Es wird versucht, ein Gerät auszuhängen, das beschäftigt ist." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Dieser Vorgang wurde bereits abgebrochen." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Nicht autorisiert, um den gewünschten Vorgang auszuführen." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Dieses Gerät ist bereits eingebunden." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Das Gerät ist nicht eingebunden." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Die gewünschte Option ist nicht gestattet." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Das Gerät ist von einem anderen Benutzer eingebunden." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Geringer Speicherplatz auf der Systempartition: {percent_used}% belegt, " "{free_space} verfügbar." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Wenig Plattenspeicherplatz" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Festplattenfehler unmittelbar bevorstehend" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6753,39 +6720,39 @@ msgstr "" "Kopieren Sie alle Daten, solange Sie noch können, und ersetzen Sie das " "Laufwerk." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Ungültiger Verzeichnisname." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Verzeichnis ist nicht vorhanden." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Pfad ist kein Verzeichnis." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Verzeichnis ist für den Benutzer nicht lesbar." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Das Verzeichnis ist für den Benutzer nicht beschreibbar." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Verzeichnis" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Unterverzeichnis (optional)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Freigeben" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Anderes Verzeichnis (unten angeben)" @@ -6823,7 +6790,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Erweitern der Root-Partition" @@ -6847,30 +6814,30 @@ msgstr "" "Nach dieser Aktion werden %(expandable_root_size)s zusätzlicher " "Speicherplatz auf der Root-Partition verfügbar." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Fehler beim Erweitern des Dateisystems: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Partition erfolgreich vergrößert." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} kann sicher entfernt werden." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Gerät kann sicher entfernt werden." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Fehler beim Auswerfen des Geräts: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6882,7 +6849,7 @@ msgstr "" "Modifikation oder Löschen von Dateien auf einem Gerät wird automatisch auf " "allen anderen Geräten reproduziert, auf denen Syncthing läuft." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6902,20 +6869,20 @@ msgstr "" "{box_name} ist nur für Benutzer der \"Admin\" oder \"Syncthing-access\"-" "Gruppe zugänglich." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Syncthing-Anwendung einstellen" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Dateisynchronisation" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6929,7 +6896,7 @@ msgstr "" "Sie den Tor Browser verwenden." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6938,40 +6905,40 @@ msgstr "" "Tor SOCKS-Port ist auf Ihrer {box_name} für interne Netzwerke auf TCP port " "9050 verfügbar." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor-Onion-Dienste" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor-Socks-Proxy" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor-Bridge-Relay" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor-Relay-Port ist verfügbar" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3-Transport registriert" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4-Transport registriert" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Zugangs-URL {url} auf TCP{kind} über Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Tor-Nutzung auf {url} über TCP{kind} bestätigen" @@ -7094,11 +7061,11 @@ msgstr "Onion-Dienste" msgid "Ports" msgstr "Ports" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Aktualisieren der Konfiguration" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Fehler beim Konfigurieren der App: {error}" @@ -7160,7 +7127,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7169,7 +7136,7 @@ msgstr "" "Tiny Tiny RSS ist ein Feedreader (RSS/Atom), der von jedem Browser aus " "genutzt werden kann, sich aber sehr wie eine normale Anwendung anfühlt." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7178,7 +7145,7 @@ msgstr "" "Wenn aktiviert, kann Tiny Tiny RSS von jedem " "Benutzer der zur Feed-Reader-Gruppe gehört, aufgerufen werden." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7187,11 +7154,11 @@ msgstr "" "verwenden Sie die URL /tt-rss-app für die " "Verbindung." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Feedreader" @@ -7199,14 +7166,14 @@ msgstr "Feedreader" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Suchen Sie nach den neuesten Software- und Sicherheitsupdates und " "installieren Sie diese." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7220,22 +7187,22 @@ msgstr "" "erachtet wird, erfolgt dieser automatisch um 02:00 Uhr, so dass alle Apps " "kurzzeitig nicht verfügbar sind." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Software-Aktualisierung" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox aktualisiert" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Distributions-Update konnte nicht gestartet werden" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7246,11 +7213,11 @@ msgstr "" "mindestens 5 GB frei sind. Das Distributions-Update wird nach 24 Stunden " "erneut versucht, falls aktiviert." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Distributions-Upgrade gestartet" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7430,44 +7397,44 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Distributions-Upgrade jetzt testen" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Fehler beim Konfigurieren von automatischen Aktualisierungen: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Automatische Systemaktualisierung aktivieren" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Automatische Aktualisierungen ausgeschaltet" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Distributions-Upgrade aktiviert" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Distributions-Upgrade deaktiviert" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Aktualisierung gestartet." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Starten der Aktualisierung fehlgeschlagen." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Häufige Funktions-Updates aktiviert." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Starten des Verteilungsupgradetests." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7478,7 +7445,7 @@ msgstr "" "muss ein Benutzerkonto Teil einer Gruppe sein, damit ein Benutzer auf die " "App zugreifen kann." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7490,15 +7457,15 @@ msgstr "" "dürfen nur Mitglieder der Gruppe admin Apps oder " "Systemeinstellungen ändern." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Benutzer und Gruppen" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Zugriff auf alle Anwendungen und Systemeinstellungen" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP-Eintrag „{search_item}“ prüfen" @@ -7518,11 +7485,11 @@ msgstr "" "Erforderlich. Bis zu 150 Zeichen. Nur englische Buchstaben, Ziffern und " "@/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Autorisierungs-Passwort" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7530,11 +7497,11 @@ msgstr "" "Geben Sie das Passwort für den Benutzer „{user}“ ein, um Kontoänderungen zu " "autorisieren." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Ungültiges Passwort." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7549,12 +7516,12 @@ msgstr "" "allen Diensten anmelden und sie können sich auch über SSH im System anmelden " "und besitzen Administratorrechte (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Erstellen des LDAP-Benutzers ist fehlgeschlagen:{error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -7575,42 +7542,42 @@ msgstr "" "eingeben, einen pro Zeile. Leerzeilen und Zeilen, die mit # beginnen, werden " "ignoriert." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Umbenennen des LDAP-Benutzers fehlgeschlagen." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Entfernen des Benutzers von der Gruppe fehlgeschlagen." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Hinzufügen eines Benutzers zur Gruppe ist fehlgeschlagen." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "SSH-Schlüssel kann nicht gesetzt werden." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Fehler beim Ändern des Benutzerstatus." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Ändern des LDAP-Benutzerpassworts ist fehlgeschlagen." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Fehler beim Hinzufügen eines neuen Benutzers zur Administratorgruppe: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Fehler beim Einschränken des Konsolenzugriffs: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Benutzerkonto wurde erstellt, Sie sind jetzt angemeldet" @@ -7627,12 +7594,12 @@ msgstr "Passwort speichern" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Benutzer anlegen" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Benutzer löschen" @@ -7673,13 +7640,19 @@ msgid "The following administrator accounts exist in the system." msgstr "Die folgenden Administratorkonten sind im System vorhanden." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Löschen Sie diese Konten von der Befehlszeile aus und aktualisieren Sie die " "Seite, um ein Konto zu erstellen, das mit %(box_name)s verwendet werden " @@ -7689,7 +7662,7 @@ msgstr "" "Schritt." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Benutzer" @@ -7723,34 +7696,34 @@ msgstr "" msgid "Save Changes" msgstr "Änderungen speichern" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Benutzer %(username)s angelegt." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Benutzer %(username)s geändert." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Benutzer bearbeiten" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Benutzer {user} gelöscht." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Löschen von LDAP-Benutzer fehlgeschlagen." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Passwort ändern" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Passwort erfolgreich geändert." @@ -8095,7 +8068,7 @@ msgstr "Verbindung zum Server löschen" msgid "Server deleted." msgstr "Server gelöscht." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8110,7 +8083,7 @@ msgstr "" "Verwaltungsoberfläche und die erstellten Webseiten sind für mobile Geräte " "geeignet." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8124,7 +8097,7 @@ msgstr "" "zugreifen. Aktivieren Sie Permalinks in der Administratoroberfläche, um " "bessere URLs für Ihre Seiten und Beiträge zu erhalten." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8135,7 +8108,7 @@ msgstr "" "wordpress/wp-admin/\">Administrationsseite, um die " "Administrationsoberfläche in Zukunft zu erreichen." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8146,12 +8119,12 @@ msgstr "" "Plugins oder Themes können auf Ihr eigenes Risiko installiert und " "aktualisiert werden." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Internetseite und Blog" @@ -8168,7 +8141,7 @@ msgstr "" "Administratoren die WordPress-Website oder den Blog aufrufen. Aktivieren Sie " "diese Option erst nach der Ersteinrichtung von WordPress." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8193,7 +8166,7 @@ msgstr "" "Einzelne Fotos können mit anderen geteilt werden, indem ein direkter Link " "gesendet wird." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8204,11 +8177,11 @@ msgstr "" "Administrator in Zoph. Für zusätzliche Benutzer müssen Konten sowohl in " "{box_name} als auch in Zoph mit demselben Benutzernamen erstellt werden." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Foto-Manager" @@ -8262,96 +8235,92 @@ msgstr "Warten auf den Start: {name}" msgid "Finished: {name}" msgstr "Fertig: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Paket {expression} ist nicht verfügbar" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Paket {package_name} ist die aktuellste Version ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Fehler beim Ausführen von apt-get" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "Installation läuft" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "herunterladen" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "Medienwechsel" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "Konfigurationsdatei: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Zeitüberschreitung beim Warten auf den Paket-Manager" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Installation der App" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Aktualisieren der App" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Fehler bei der Installation der App: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Fehler beim Aktualisieren der App: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Fehler bei der Installation der App: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Fehler beim Aktualisieren der App: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "App installiert." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "App aktualisiert" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Deinstallation der App" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Fehler bei der Deinstallation der App: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Fehler bei der Deinstallation der App: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "App deinstalliert." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Aktualisieren von App-Paketen" @@ -8413,53 +8382,54 @@ msgstr "Installation" msgid "Service %(service_name)s is not running." msgstr "Dienst %(service_name)s läuft nicht." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Kernfunktionalität und Weboberfläche für %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Startseite" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Startseite" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Apps" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Apps" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " System" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "System" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Passwort ändern" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Herunterfahren" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Abmelden" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Sprache wählen" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Anmelden" @@ -8749,6 +8719,77 @@ msgstr "vor der Deinstallation von {app_id}" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "DNSSEC einschalten" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Domain-Name-System-Sicherheitserweiterungen (DNSSEC) aktivieren" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Firewalldaemon läuft nicht. Bitte starten. Die Firewall ist standardmäßig " +#~ "auf %(box_name)s aktiviert. Auf jedem Debian-basierten System (wie " +#~ "%(box_name)s) kann sie über das Kommando „service firewalld start“ oder " +#~ "bei einem System mit systemd mit „systemctl start firewalld“ gestartet " +#~ "werden." + +#~ msgid "Migrate to ECC" +#~ msgstr "" +#~ "Migration zur ECC-Kryptographie (Kryptographie basierend auf elliptischen " +#~ "Kurven)" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Ihre OpenVPN-Installation verwendet derzeit RSA. Der Umstieg auf die " +#~ "moderne Elliptische-Kurven-Kryptographie verbessert die Geschwindigkeit " +#~ "des Verbindungsaufbaus und die Sicherheit. Dieser Vorgang unumkehrbar. " +#~ "Sie sollte auf den meisten Einplatinencomputern nur wenige Minuten dauern." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Alle neuen Installationen von OpenVPN auf %(box_name)s verwenden " +#~ "standardmäßig ECC. Wir empfehlen, so bald wie möglich zu wechseln." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Warnung: Bestehende Client-Profile werden durch diese Operation " +#~ "ungültig. Alle OpenVPN-Benutzer auf %(box_name)s müssen ihre neuen " +#~ "Profile herunterladen. Für die Verbindung zu diesem Server sollten " +#~ "OpenVPN-Clients verwendet werden, die mit ECC kompatibel sind." + +#~ msgid "Migrate" +#~ msgstr "Migrieren" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "SSH-Authentifizierung mit Passwort deaktiviert." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "SSH-Authentifizierung mit Passwort aktiviert." + +#~ msgid "Error running apt-get" +#~ msgstr "Fehler beim Ausführen von apt-get" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Kernfunktionalität und Weboberfläche für %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Netzwerkverbindungen" diff --git a/plinth/locale/django.pot b/plinth/locale/django.pot index 154274480..1efa403c4 100644 --- a/plinth/locale/django.pot +++ b/plinth/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -109,17 +109,17 @@ msgstr "" msgid "{box_name} Web Interface (Plinth)" msgstr "" -#: plinth/modules/apache/components.py:126 +#: plinth/modules/apache/components.py:121 #, python-brace-format msgid "Access URL {url} on tcp{kind}" msgstr "" -#: plinth/modules/apache/components.py:129 +#: plinth/modules/apache/components.py:124 #, python-brace-format msgid "Access URL {url}" msgstr "" -#: plinth/modules/avahi/__init__.py:26 +#: plinth/modules/avahi/__init__.py:24 #, python-brace-format msgid "" "Service discovery allows other devices on the network to discover your " @@ -130,48 +130,48 @@ msgid "" "network." msgstr "" -#: plinth/modules/avahi/__init__.py:49 +#: plinth/modules/avahi/__init__.py:47 msgid "Service Discovery" msgstr "" -#: plinth/modules/avahi/__init__.py:62 +#: plinth/modules/avahi/__init__.py:60 msgid "Local Network Domain" msgstr "" -#: plinth/modules/backups/__init__.py:27 +#: plinth/modules/backups/__init__.py:24 msgid "Backups allows creating and managing backup archives." msgstr "" -#: plinth/modules/backups/__init__.py:48 plinth/modules/backups/__init__.py:199 -#: plinth/modules/backups/__init__.py:244 +#: plinth/modules/backups/__init__.py:44 plinth/modules/backups/__init__.py:169 +#: plinth/modules/backups/__init__.py:214 msgid "Backups" msgstr "" -#: plinth/modules/backups/__init__.py:196 +#: plinth/modules/backups/__init__.py:166 msgid "" "Enable an automatic backup schedule for data safety. Prefer an encrypted " "remote backup location or an extra attached disk." msgstr "" -#: plinth/modules/backups/__init__.py:202 +#: plinth/modules/backups/__init__.py:172 msgid "Enable a Backup Schedule" msgstr "" -#: plinth/modules/backups/__init__.py:206 -#: plinth/modules/backups/__init__.py:253 -#: plinth/modules/storage/__init__.py:326 +#: plinth/modules/backups/__init__.py:176 +#: plinth/modules/backups/__init__.py:223 plinth/modules/privacy/__init__.py:71 +#: plinth/modules/storage/__init__.py:313 #, python-brace-format msgid "Go to {app_name}" msgstr "" -#: plinth/modules/backups/__init__.py:241 +#: plinth/modules/backups/__init__.py:211 #, python-brace-format msgid "" "A scheduled backup failed. Past {error_count} attempts for backup did not " "succeed. The latest error is: {error_message}" msgstr "" -#: plinth/modules/backups/__init__.py:249 +#: plinth/modules/backups/__init__.py:219 msgid "Error During Backup" msgstr "" @@ -303,7 +303,7 @@ msgstr "" msgid "Key in Repository" msgstr "" -#: plinth/modules/backups/forms.py:176 plinth/modules/searx/forms.py:15 +#: plinth/modules/backups/forms.py:176 plinth/modules/searx/forms.py:14 msgid "None" msgstr "" @@ -367,37 +367,37 @@ msgstr "" msgid "Select verified SSH public key" msgstr "" -#: plinth/modules/backups/repository.py:34 +#: plinth/modules/backups/repository.py:30 msgid "" "Connection refused - make sure you provided correct credentials and the " "server is running." msgstr "" -#: plinth/modules/backups/repository.py:41 +#: plinth/modules/backups/repository.py:37 msgid "Connection refused" msgstr "" -#: plinth/modules/backups/repository.py:48 +#: plinth/modules/backups/repository.py:44 msgid "Repository not found" msgstr "" -#: plinth/modules/backups/repository.py:53 +#: plinth/modules/backups/repository.py:49 msgid "Incorrect encryption passphrase" msgstr "" -#: plinth/modules/backups/repository.py:58 +#: plinth/modules/backups/repository.py:54 msgid "SSH access denied" msgstr "" -#: plinth/modules/backups/repository.py:64 +#: plinth/modules/backups/repository.py:60 msgid "Repository path is neither empty nor is an existing backups repository." msgstr "" -#: plinth/modules/backups/repository.py:147 +#: plinth/modules/backups/repository.py:145 msgid "Existing repository is not encrypted." msgstr "" -#: plinth/modules/backups/repository.py:331 +#: plinth/modules/backups/repository.py:335 #, python-brace-format msgid "{box_name} storage" msgstr "" @@ -452,7 +452,7 @@ msgid "Create Location" msgstr "" #: plinth/modules/backups/templates/backups_add_repository.html:19 -#: plinth/modules/gitweb/views.py:54 +#: plinth/modules/gitweb/views.py:51 msgid "Create Repository" msgstr "" @@ -675,7 +675,7 @@ msgstr "" msgid "Mounting failed" msgstr "" -#: plinth/modules/bepasty/__init__.py:21 +#: plinth/modules/bepasty/__init__.py:16 msgid "" "bepasty is a web application that allows large files to be uploaded and " "shared. Text and code snippets can also be pasted and shared. Text, image, " @@ -683,7 +683,7 @@ msgid "" "can be set to expire after a time period." msgstr "" -#: plinth/modules/bepasty/__init__.py:25 +#: plinth/modules/bepasty/__init__.py:20 msgid "" "bepasty does not use usernames for login. It only uses passwords. For each " "password, a set of permissions can be selected. Once you have created a " @@ -691,7 +691,7 @@ msgid "" "permissions." msgstr "" -#: plinth/modules/bepasty/__init__.py:29 +#: plinth/modules/bepasty/__init__.py:24 msgid "" "You can also create multiple passwords with the same set of privileges, and " "distribute them to different people or groups. This will allow you to later " @@ -699,39 +699,39 @@ msgid "" "the list." msgstr "" -#: plinth/modules/bepasty/__init__.py:36 plinth/modules/bepasty/__init__.py:45 +#: plinth/modules/bepasty/__init__.py:31 plinth/modules/bepasty/__init__.py:40 msgid "Read a file, if a web link to the file is available" msgstr "" -#: plinth/modules/bepasty/__init__.py:37 +#: plinth/modules/bepasty/__init__.py:32 msgid "Create or upload files" msgstr "" -#: plinth/modules/bepasty/__init__.py:38 +#: plinth/modules/bepasty/__init__.py:33 msgid "List all files and their web links" msgstr "" -#: plinth/modules/bepasty/__init__.py:39 +#: plinth/modules/bepasty/__init__.py:34 msgid "Delete files" msgstr "" -#: plinth/modules/bepasty/__init__.py:40 +#: plinth/modules/bepasty/__init__.py:35 msgid "Administer files: lock/unlock files" msgstr "" -#: plinth/modules/bepasty/__init__.py:44 +#: plinth/modules/bepasty/__init__.py:39 msgid "None, password is always required" msgstr "" -#: plinth/modules/bepasty/__init__.py:46 +#: plinth/modules/bepasty/__init__.py:41 msgid "List and read all files" msgstr "" -#: plinth/modules/bepasty/__init__.py:61 plinth/modules/bepasty/manifest.py:6 +#: plinth/modules/bepasty/__init__.py:56 plinth/modules/bepasty/manifest.py:6 msgid "bepasty" msgstr "" -#: plinth/modules/bepasty/__init__.py:63 +#: plinth/modules/bepasty/__init__.py:58 msgid "File & Snippet Sharing" msgstr "" @@ -745,7 +745,7 @@ msgstr "" #: plinth/modules/bepasty/forms.py:27 #: plinth/modules/bepasty/templates/bepasty.html:30 -#: plinth/modules/users/forms.py:108 plinth/modules/users/forms.py:234 +#: plinth/modules/users/forms.py:111 plinth/modules/users/forms.py:235 msgid "Permissions" msgstr "" @@ -778,35 +778,35 @@ msgstr "" #: plinth/modules/bepasty/templates/bepasty.html:29 #: plinth/modules/dynamicdns/forms.py:91 plinth/modules/networks/forms.py:213 -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password" msgstr "" -#: plinth/modules/bepasty/views.py:22 +#: plinth/modules/bepasty/views.py:19 msgid "admin" msgstr "" -#: plinth/modules/bepasty/views.py:23 +#: plinth/modules/bepasty/views.py:20 msgid "editor" msgstr "" -#: plinth/modules/bepasty/views.py:24 +#: plinth/modules/bepasty/views.py:21 msgid "viewer" msgstr "" -#: plinth/modules/bepasty/views.py:49 +#: plinth/modules/bepasty/views.py:47 msgid "Read" msgstr "" -#: plinth/modules/bepasty/views.py:50 +#: plinth/modules/bepasty/views.py:48 msgid "Create" msgstr "" -#: plinth/modules/bepasty/views.py:51 +#: plinth/modules/bepasty/views.py:49 msgid "List" msgstr "" -#: plinth/modules/bepasty/views.py:52 +#: plinth/modules/bepasty/views.py:50 #: plinth/modules/email/templates/email-aliases.html:24 #: plinth/modules/letsencrypt/templates/letsencrypt.html:86 #: plinth/modules/networks/templates/connection_show.html:56 @@ -818,41 +818,41 @@ msgstr "" msgid "Delete" msgstr "" -#: plinth/modules/bepasty/views.py:53 +#: plinth/modules/bepasty/views.py:51 msgid "Admin" msgstr "" -#: plinth/modules/bepasty/views.py:90 plinth/modules/searx/views.py:40 -#: plinth/modules/searx/views.py:51 plinth/modules/tor/views.py:75 +#: plinth/modules/bepasty/views.py:88 plinth/modules/searx/views.py:35 +#: plinth/modules/searx/views.py:46 plinth/modules/tor/views.py:73 #: plinth/modules/zoph/views.py:71 msgid "Configuration updated." msgstr "" -#: plinth/modules/bepasty/views.py:93 plinth/modules/email/views.py:48 -#: plinth/modules/gitweb/views.py:121 plinth/modules/searx/views.py:43 -#: plinth/modules/searx/views.py:54 plinth/modules/zoph/views.py:74 +#: plinth/modules/bepasty/views.py:91 plinth/modules/email/views.py:48 +#: plinth/modules/gitweb/views.py:117 plinth/modules/searx/views.py:38 +#: plinth/modules/searx/views.py:49 plinth/modules/zoph/views.py:74 msgid "An error occurred during configuration." msgstr "" -#: plinth/modules/bepasty/views.py:105 +#: plinth/modules/bepasty/views.py:103 msgid "Password added." msgstr "" -#: plinth/modules/bepasty/views.py:110 +#: plinth/modules/bepasty/views.py:108 msgid "Add Password" msgstr "" -#: plinth/modules/bepasty/views.py:127 +#: plinth/modules/bepasty/views.py:122 msgid "Password deleted." msgstr "" -#: plinth/modules/bind/__init__.py:25 +#: plinth/modules/bind/__init__.py:17 msgid "" "BIND enables you to publish your Domain Name System (DNS) information on the " "Internet, and to resolve DNS queries for your user devices on your network." msgstr "" -#: plinth/modules/bind/__init__.py:29 +#: plinth/modules/bind/__init__.py:21 #, python-brace-format msgid "" "Currently, on {box_name}, BIND is only used to resolve DNS queries for other " @@ -860,31 +860,23 @@ msgid "" "connection from {box_name}." msgstr "" -#: plinth/modules/bind/__init__.py:74 +#: plinth/modules/bind/__init__.py:40 msgid "BIND" msgstr "" -#: plinth/modules/bind/__init__.py:75 +#: plinth/modules/bind/__init__.py:41 msgid "Domain Name Server" msgstr "" -#: plinth/modules/bind/forms.py:20 +#: plinth/modules/bind/forms.py:19 msgid "Forwarders" msgstr "" -#: plinth/modules/bind/forms.py:21 +#: plinth/modules/bind/forms.py:20 msgid "" "A list DNS servers, separated by space, to which requests will be forwarded" msgstr "" -#: plinth/modules/bind/forms.py:25 -msgid "Enable DNSSEC" -msgstr "" - -#: plinth/modules/bind/forms.py:26 -msgid "Enable Domain Name System Security Extensions" -msgstr "" - #: plinth/modules/bind/templates/bind.html:11 msgid "Serving Domains" msgstr "" @@ -916,19 +908,20 @@ msgstr "" msgid "Refresh IP address and domains" msgstr "" -#: plinth/modules/bind/views.py:71 plinth/modules/config/views.py:99 -#: plinth/modules/coturn/views.py:41 plinth/modules/deluge/views.py:42 -#: plinth/modules/dynamicdns/views.py:78 plinth/modules/ejabberd/views.py:96 -#: plinth/modules/email/views.py:45 plinth/modules/matrixsynapse/views.py:126 -#: plinth/modules/minetest/views.py:69 plinth/modules/mumble/views.py:37 -#: plinth/modules/pagekite/forms.py:78 plinth/modules/quassel/views.py:29 -#: plinth/modules/roundcube/views.py:32 plinth/modules/shadowsocks/views.py:59 -#: plinth/modules/transmission/views.py:43 plinth/modules/ttrss/views.py:26 -#: plinth/modules/wordpress/views.py:37 +#: plinth/modules/bind/views.py:61 plinth/modules/config/views.py:98 +#: plinth/modules/coturn/views.py:40 plinth/modules/deluge/views.py:35 +#: plinth/modules/dynamicdns/views.py:78 plinth/modules/ejabberd/views.py:95 +#: plinth/modules/email/views.py:45 plinth/modules/matrixsynapse/views.py:128 +#: plinth/modules/minetest/views.py:55 plinth/modules/mumble/views.py:37 +#: plinth/modules/pagekite/forms.py:74 plinth/modules/privacy/views.py:36 +#: plinth/modules/quassel/views.py:29 plinth/modules/roundcube/views.py:32 +#: plinth/modules/shadowsocks/views.py:53 plinth/modules/ssh/views.py:52 +#: plinth/modules/transmission/views.py:43 plinth/modules/ttrss/views.py:31 +#: plinth/modules/wordpress/views.py:31 msgid "Configuration updated" msgstr "" -#: plinth/modules/calibre/__init__.py:26 +#: plinth/modules/calibre/__init__.py:22 #, python-brace-format msgid "" "calibre server provides online access to your e-book collection. You can " @@ -936,7 +929,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/calibre/__init__.py:29 +#: plinth/modules/calibre/__init__.py:25 msgid "" "You can organize your e-books, extract and edit their metadata, and perform " "advanced search. calibre can import, export, or convert across a wide range " @@ -945,35 +938,35 @@ msgid "" "highlighted text. Content distribution using OPDS is currently not supported." msgstr "" -#: plinth/modules/calibre/__init__.py:35 +#: plinth/modules/calibre/__init__.py:31 msgid "" "Only users belonging to calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1019,20 +1012,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1070,24 +1063,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1183,47 +1176,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1231,7 +1224,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1461,11 +1454,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1577,7 +1570,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1632,13 +1625,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1760,14 +1753,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1775,7 +1768,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1785,13 +1778,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1916,7 +1909,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1924,7 +1917,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1944,61 +1937,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2044,7 +2028,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2055,73 +2039,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2165,19 +2149,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2470,7 +2454,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2478,31 +2462,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2539,14 +2523,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2555,15 +2539,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2617,41 +2601,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2659,11 +2643,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2709,7 +2693,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2727,7 +2711,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2737,7 +2721,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2745,15 +2729,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2816,41 +2800,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2860,14 +2844,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2948,7 +2932,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2956,7 +2940,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2965,18 +2949,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3045,35 +3029,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3082,11 +3066,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3131,7 +3115,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3290,19 +3274,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3648,7 +3632,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3753,7 +3737,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3769,7 +3753,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3782,7 +3766,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4318,7 +4302,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4329,20 +4313,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4352,61 +4336,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4415,33 +4367,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4450,87 +4402,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4564,29 +4516,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4628,8 +4580,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4671,6 +4623,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4702,7 +4685,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4713,7 +4696,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4733,7 +4716,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4743,19 +4726,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4814,7 +4797,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4881,7 +4864,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4894,13 +4877,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4909,31 +4892,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5011,15 +4994,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5045,51 +5028,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5242,14 +5225,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5258,97 +5241,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5385,26 +5368,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5412,14 +5395,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5513,7 +5496,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5561,57 +5544,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5619,7 +5602,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5652,14 +5635,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5672,7 +5647,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5680,143 +5655,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5850,7 +5825,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5868,30 +5843,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5899,7 +5874,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5911,20 +5886,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5933,47 +5908,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6071,11 +6046,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6127,31 +6102,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6159,12 +6134,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6172,33 +6147,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6346,51 +6321,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6398,15 +6373,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6424,21 +6399,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6447,12 +6422,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6468,41 +6443,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6519,12 +6494,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6562,17 +6537,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6603,34 +6578,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6939,7 +6914,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6948,7 +6923,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6957,26 +6932,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6990,7 +6965,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7003,7 +6978,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7011,11 +6986,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7064,96 +7039,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7204,53 +7175,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/el/LC_MESSAGES/django.po b/plinth/locale/el/LC_MESSAGES/django.po index 224513bbf..2a9d3eced 100644 --- a/plinth/locale/el/LC_MESSAGES/django.po +++ b/plinth/locale/el/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:20+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Greek calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Name of the repository" msgid "Name of the new library" msgstr "Όνομα του αποθετηρίου" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 #, fuzzy #| msgid "A share with this name already exists." msgid "A library with this name already exists." @@ -1157,24 +1149,24 @@ msgstr "" msgid "Delete library %(library)s" msgstr "Διαγραφή ιστότοπου %(site)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 #, fuzzy #| msgid "Repository created." msgid "Library created." msgstr "Το αποθετήριο δημιουργήθηκε." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 #, fuzzy #| msgid "An error occurred while creating the repository." msgid "An error occurred while creating the library." msgstr "Παρουσιάστηκε σφάλμα κατά τη δημιουργία του αποθετηρίου." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "το {name} διαγράφηκε." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Δεν ήταν δυνατή η διαγραφή του {name}: {error}" @@ -1219,7 +1211,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Διαχείριση διακομιστή" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1228,18 +1220,18 @@ msgstr "" "υπολογιστή, το όνομα διαδικτύου σας, την κεντρική ιστοσελίδα του διακομιστή " "διαδικτύου κλπ." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Γενικές ρυθμίσεις" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Ρυθμίσετε" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1354,49 +1346,49 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Σφάλμα κατά τη ρύθμιση του ονόματος του υπολογιστή: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "To όνομα του υπολογιστη ρυθμίστηκε επιτυχώς" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Σφάλμα κατά τη ρύθμιση ονόματος διδαδικτύου: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "To όνομα διαδικτύου ρυθμίστηκε επιτυχώς" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" "Σφάλμα κατά τη ρύθμιση της αρχικής σελίδας διακομιστή διαδικτύου: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Aρχική σελίδα διακομιστή διαδικτύου ρυθμίστηκε" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" "Παρουσιάστηκε σφάλμα κατά την αλλαγή σε προηγμένη λειτουργία: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Εμφανίζονται προηγμένες εφαρμογές και λειτουργίες" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Απόκρυψη προηγμένων εφαρμογών και χαρακτηριστικών" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1404,7 +1396,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as freedns." "afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Πελάτης δυναμικού DNS" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Δυναμικό όνομα διαδικτύου" @@ -1825,7 +1817,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1894,7 +1886,7 @@ msgstr "Διαγραφή σύνδεσης" msgid "Already up-to-date" msgstr "Ενεργοποίηση αυτόματων ενημερώσεων" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1903,7 +1895,7 @@ msgstr "" "μπορείτε να εκτελέσετε και να ρυθμίσετε τις παραμέτρους του διακομιστή XMPP, " "που ονομάζεται ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientπιστοποιητικά για το {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Διακομιστής συνομιλίας" @@ -2050,14 +2042,14 @@ msgstr "" "%(domainname)s. Μπορείτε να ρυθμίσετε το όνομα της υπηρεσίας στο Ρυθμίστε page." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2065,7 +2057,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2075,13 +2067,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2224,7 +2216,7 @@ msgstr "Θύρα" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2236,7 +2228,7 @@ msgstr "" "προστασίας ενεργοποιημένο και η σωστή ρύθμιση παραμέτρων μειώνει τον κίνδυνο " "απειλών προερχόμενων από το Internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall (τείχος προστασίας)" @@ -2256,54 +2248,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Η θύρα {name} ({details}) δεν είναι διαθέσιμη για εξωτερικά δίκτυα" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"To πρόγραμμα τείχους προστασίας δεν εκτελείται. Παρακαλείστε να το τρέξετε. " -"Το τείχος προστασίας εμφανίζεται ενεργοποιημένο από προεπιλογή στο " -"%(box_name)s. Σε οποιοδήποτε σύστημα που βασίζεται στο Debian (όπως το " -"%(box_name)s) μπορείτε να το εκτελέσετε χρησιμοποιώντας την εντολή ' service " -"firewalld start ' ή σε περίπτωση ενός συστήματος με systemd ' systemctl " -"start firewalld '." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Υπηρεσία/θύρα" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Ενεργοποιήθηκε" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Απενεργοποιήθηκε" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Επιτρέπεται" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Επιτρέπεται (μόνο εσωτερικά)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Επιτρέπεται (εξωτερικά μόνο)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Αποκλείστηκε" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2313,13 +2290,13 @@ msgstr "" "υπηρεσία, επιτρέπεται επίσης στο τείχος προστασίας και όταν απενεργοποιείτε " "μια υπηρεσία είναι επίσης απενεργοποιημένη στο τείχος προστασίας." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Για προχωρημένους" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2370,7 +2347,7 @@ msgstr "Έναρξη εγκατάστασης" msgid "Setup Complete" msgstr "Η εγκατάσταση ολοκληρώθηκε" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2389,7 +2366,7 @@ msgstr "" "πολλαπλές διαθέσιμες γραφικές εφαρμογές-πελάτες. Και μπορείτε να μοιραστείτε " "τον κώδικά σας με τους ανθρώπους σε όλο τον κόσμο." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2397,75 +2374,75 @@ msgstr "" "Για να μάθετε περισσότερα για το git μάθημα git." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Πρόσβαση ανάγνωσης και εγγραφής σε αποθετήρια Git" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Απλό Hosting Git" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Μη έγκυρη διεύθυνση URL για το αποθετήριο." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Μη έγκυρο όνομα αποθετηρίου." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Όνομα νέου αποθετηρίου ή διεύθυνσης URL για την εισαγωγή υπάρχοντος " "αποθετηρίου." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Περιγραφή του αποθετηρίου" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Προαιρετικά, για την εμφάνιση στην Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Όνομα κατόχου αποθετηρίου" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Ιδιωτικό αποθετήριο" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" "Να επιτρέπεται μόνο σε εξουσιοδοτημένους χρήστες η πρόσβαση σε αυτό το " "αποθετήριο." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Υπάρχει ήδη ένα αποθετήριο με αυτό το όνομα." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Όνομα του αποθετηρίου" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" "Μια αλφαριθμητική συμβολοσειρά που προσδιορίζει με μοναδικό τρόπο ένα " "αποθετήριο." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Default Skin" msgid "Default branch" msgstr "Προεπιλεγμένη εμφάνιση" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2511,19 +2488,19 @@ msgstr "Διαγραφή αποθετηρίου Git %(name)s" msgid "Delete this repository permanently?" msgstr "Να διαγραφεί μόνιμα αυτό το αποθετήριο;" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Το αποθετήριο δημιουργήθηκε." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Παρουσιάστηκε σφάλμα κατά τη δημιουργία του αποθετηρίου." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "To αποθετήριο τροποποιήθηκε." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Τροποποίηση αποθετηρίου" @@ -2906,7 +2883,7 @@ msgstr "Σχετικά με το {box_name}" msgid "{box_name} Manual" msgstr "Εγχειρίδιο για το {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2918,7 +2895,7 @@ msgstr "" "παρακολούθηση. Το i2p παρέχει ανωνυμία κατά την αποστολή κρυπτογραφημένης " "κυκλοφορίας μέσα από ένα εθελοντικό δίκτυο διανεμημένο σε όλο τον κόσμο." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2926,7 +2903,7 @@ msgstr "" "Βρείτε περισσότερες πληροφορίες σχετικά με το έργο τους Ι2Ρ." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2934,19 +2911,19 @@ msgstr "" "Η πρώτη επίσκεψη στο παρεχόμενο δικτυακό περιβάλλον θα ξεκινήσει τη " "διαδικασία ρύθμισης." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Διαχείριση εφαρμογής I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Δίκτυο ανωνυμίας" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "Διακομιστής μεσολάβησης I2P" @@ -2997,7 +2974,7 @@ msgstr "" "to-peer δίκτυο. Κατεβάστε τα αρχεία με την προσθήκη torrents ή δημιουργήστε " "ένα νέο torrent για να μοιραστείτε ένα αρχείο." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -3007,7 +2984,7 @@ msgstr "" "ελαφριές γλώσσες σήμανσης, όπως Markdown και κοινές λειτουργίες ιστολογίου, " "όπως σχόλια και τροφοδοσίες RSS." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -3022,15 +2999,15 @@ msgstr "" "\"{users_url}\">ρυθμίσεις μπορεί να γίνει ρύθμιση παραμέτρων χρήστη και " "να αλλάξετε τα δικαιώματα ή να προσθέσετε νέους χρήστες." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki και Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Προβολή και επεξεργασία εφαρμογών wiki" @@ -3087,43 +3064,43 @@ msgstr "" "σχόλια, συμπεριλαμβανομένου του ιστορικού αναθεωρήσεων. Να διαγραφεί " "οριστικά αυτό το wiki ή το blog;" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Δημιουργήθηκε το wiki {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Δεν ήταν δυνατή η δημιουργία wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Δημιουργήθηκε το blog {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Δεν ήταν δυνατή η δημιουργία ιστολογίου: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} διαγράφηκε." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Δεν ήταν δυνατή η διαγραφή του {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" "infinoted είναι ένας διακομιστής για Γκόμπι, ένα πρόγραμμα που μπορείτε να " "συνεργαστείτε στην επεξεργασία κειμένου." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3135,11 +3112,11 @@ msgstr "" "επιλέξτε \"σύνδεση στο διακομιστή\" και πληκτρολογήστε το όνομα διαδικτύου " "σας για το {box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby Server" @@ -3187,7 +3164,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Πληροφορίες άδειας χρήσης JavaScript" @@ -3207,7 +3184,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Πρόγραμμα-πελάτης συνομιλίας" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3223,7 +3200,7 @@ msgstr "" "αποδεικνύοντας ότι είναι ο ιδιοκτήτης ενός ονόματος στην υπηρεσία Let's " "Encrypt, μια αρχή έκδοσης πιστοποιητικών (CA)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3237,15 +3214,15 @@ msgstr "" "letsencrypt.org/repository/\">Συμφωνία Συνδρομητή Lets Encrypt πριν από " "τη χρήση αυτής της υπηρεσίας." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Πιστοποιητικά" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3310,7 +3287,7 @@ msgstr "" "Δεν έχουν ρυθμιστεί ονόματα διαδικτύου Ρυθμίσετε " "όνομα διαδικτύου για να μπορείτε να αποκτήσετε πιστοποιητικά για αυτό." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3319,34 +3296,34 @@ msgstr "" "Το πιστοποιητικό ακυρώθηκε με επιτυχία για τον όνομα {domain}. Αυτό μπορεί " "να διαρκέσει λίγα λεπτά για να τεθεί σε ισχύ." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Απέτυχε η ανάκληση του πιστοποιητικού για το όνομα {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Το πιστοποιητικό αποκτήθηκε με επιτυχία για το όνομα {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Αποτυχία λήψης πιστοποιητικού για το όνομα {domain} {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Το πιστοποιητικό διαγράφηκε επιτυχώς για το όνομα {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Αποτυχία διαγραφής πιστοποιητικού για το όνομα {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3364,14 +3341,14 @@ msgstr "" "να συνομιλήσουν με τους χρήστες σε όλες τις άλλες διακομιστές Matrix μέσω " "ομοσπονδίας." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3479,7 +3456,7 @@ msgstr "" "TLS πιστοποιητικό. Μεταβείτε στη διεύθυνση " "Lets Encrypt για να αποκτήσετε ένα." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3492,7 +3469,7 @@ msgstr "" "χρησιμοποιήσετε το wiki για να φιλοξενήσετε μια ιστοσελίδα που μοιάζει με " "wiki, να πάρετε σημειώσεις ή να συνεργαστείτε με φίλους σε έργα." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3507,7 +3484,7 @@ msgstr "" "λογαριασμούς χρηστών από το ίδιο το wiki, πηγαίνοντας στη σελίδα Δημιουργία λογαριασμού." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3515,12 +3492,12 @@ msgstr "" "Όποιος έχει μια διεύθυνση URL για αυτό το wiki μπορεί να το διαβάσει. Μόνο " "οι χρήστες που είναι συνδεδεμένοι μπορούν να κάνουν αλλαγές στο περιεχόμενο." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "Mediawiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3609,39 +3586,39 @@ msgstr "" "Κωδικός πρόσβασης που χρησιμοποιείται για την κρυπτογράφηση δεδομένων. " "Πρέπει να ταιριάζει με τον κωδικό πρόσβασης του διακομιστή." -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Η δημόσια εγγραφή ενεργοποιήθηκε" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Οι δημόσιες εγγραφές είναι απενεργοποιημένες" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Η ιδιωτική λειτουργία είναι ενεργοποιημένη" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Η ιδιωτική λειτουργία απενεργοποιήθηκε" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Η προεπιλεγμένη εμφάνιση άλλαξε" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "To όνομα διαδικτύου ρυθμίστηκε επιτυχώς" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "To όνομα διαδικτύου ρυθμίστηκε επιτυχώς" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3655,11 +3632,11 @@ msgstr "" "συνδεθείτε με το διακομιστή, ένας Minetest πελάτη είναι απαραίτητος." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Μπλοκ Sandbox" @@ -3713,7 +3690,7 @@ msgstr "" msgid "Address" msgstr "Διεύθυνση" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3913,7 +3890,7 @@ msgstr "Secure Shell" msgid "Services" msgstr "Υπηρεσία" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3922,7 +3899,7 @@ msgstr "" "Ethernet, Wi-Fi ή PPPoE. Μοιραστείτε αυτήν τη σύνδεση με άλλες συσκευές στο " "δίκτυο." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3930,7 +3907,7 @@ msgstr "" "Οι συσκευές που διαχειρίζονται μέσω άλλων μεθόδων ενδέχεται να μην είναι " "διαθέσιμες για ρύθμιση παραμέτρων εδώ." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Δίκτυα" @@ -4304,7 +4281,7 @@ msgstr "Επεξεργασία σύνδεσης" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Επεξεργασία" @@ -4409,7 +4386,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Μέθοδος" @@ -4425,7 +4402,7 @@ msgstr "Διακομιστής DNS" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Προεπιλογή" @@ -4438,7 +4415,7 @@ msgid "This connection is not active." msgstr "Αυτή η σύνδεση δεν είναι ενεργή." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Ασφάλεια" @@ -5043,7 +5020,7 @@ msgstr "Η σύνδεση {name} διαγράφηκε." msgid "Failed to delete connection: Connection not found." msgstr "Απέτυχε η διαγραφή της σύνδεσης: η σύνδεση δεν βρέθηκε." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -5061,22 +5038,22 @@ msgstr "" "επίσης να αποκτήσετε πρόσβαση στο υπόλοιπο Internet μέσω του {box_name} για " "πρόσθετη ασφάλεια και ανωνυμία." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection Type" msgid "Connect to VPN services" msgstr "Τύπος σύνδεσης" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Εικονικό ιδιωτικό δίκτυο" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5088,50 +5065,21 @@ msgstr " Λήψη προφί msgid "Tunnelblick" msgstr "TunnelBlick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -#, fuzzy -#| msgid "Moderate" -msgid "Migrate" -msgstr "Μέτριο" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Προφίλ" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Για να συνδεθείτε στο VPN του %(box_name)s, πρέπει να κάνετε λήψη ενός " @@ -5141,18 +5089,19 @@ msgstr "" "περισσότερα...\" Προτεινόμενα προγράμματα-πελάτες και οδηγίες σχετικά με τον " "τρόπο διαμόρφωσης τους." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Το προφίλ είναι συγκεκριμένο για κάθε χρήστη του %(box_name)s. Κρατήστε το " "μυστικό." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Λήψη του προφίλ μου" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5165,19 +5114,19 @@ msgstr "" "υπηρεσίες δεν είναι προσβάσιμες από το υπόλοιπο Internet. Αυτό περιλαμβάνει " "τις ακόλουθες καταστάσεις:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "το {box_name} βρίσκεται πίσω από ένα περιορισμένο τείχος προστασίας." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "το {box_name} είναι συνδεδεμένο σε έναν (ασύρματο) δρομολογητή, τον οποίο " "δεν ελέγχετε." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5185,7 +5134,7 @@ msgstr "" "Ο παροχέας ιντερνετ δεν σας παρέχει εξωτερική διεύθυνση IP και αντίθετα " "παρέχει σύνδεση στο Internet μέσω δικτύου NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5193,11 +5142,11 @@ msgstr "" "Ο παροχέας ιντερνετ δεν σας παρέχει μια στατική διεύθυνση IP και η διεύθυνση " "IP αλλάζει κάθε φορά που συνδέεστε στο Internet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Ο παροχέας ιντερνετ περιορίζει τις εισερχόμενες συνδέσεις." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5211,23 +5160,23 @@ msgstr "" "παράδειγμα pagekite.net . Στο μέλλον " "μπορεί να είναι δυνατή η χρήση του {box_name} ενός φίλου σας για αυτό." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Δημόσια ορατότητα" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "Όνομα διαδικτύου Pagekite" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Όνομα διαδικτύου διακομιστή" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5235,31 +5184,31 @@ msgstr "" "Επιλέξτε το διακομιστή pagekite. Ορίστε το \"pagekite.net\" για να " "χρησιμοποιήσετε τον προεπιλεγμένο διακομιστή pagekite.net." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Θύρα διακομιστή" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Θύρα του διακομιστή σελιδοποίησης (προεπιλογή: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite όνομα" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Παράδειγμα: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Μη έγκυρο όνομα kite" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite μυστικό" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5267,27 +5216,27 @@ msgstr "" "Ένα μυστικό που σχετίζεται με το kite ή το προεπιλεγμένο μυστικό για το " "λογαριασμό σας, εάν δεν αναθέσετε καινούριο." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "Πρωτόκολλο" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "εξωτερική (frontend) θύρα" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "εσωτερική (freedombox) θύρα" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Ενεργοποίηση δευτερευόντων ονομάτων διαδικτύου" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Διαγράφηκε η διαμορφωμένη υπηρεσία" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 #, fuzzy #| msgid "" #| "This service is available as a standard service. Please use the " @@ -5297,11 +5246,11 @@ msgstr "" "Αυτή η υπηρεσία είναι διαθέσιμη ως πρότυπη υπηρεσία. Παρακαλούμε να " "χρησιμοποιήσετε την σελίδα \"Πρότυπες Υπηρεσίες\" για να το ενεργοποιήσετε." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Προστέθηκε τροποποιημένη υπηρεσία" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Αυτή η υπηρεσία υπάρχει ήδη" @@ -5339,30 +5288,30 @@ msgstr "" "παράδειγμα, HTTPS, στις θύρες εκτός από 443 είναι γνωστό ότι προκαλούν " "προβλήματα." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Διακομιστής Διαδικτύου (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" "Η τοποθεσία θα είναι διαθέσιμη στο http://{0} " -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Διακομιστής Διαδικτύου (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Το Site θα είναι διαθέσιμο στο https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5409,8 +5358,8 @@ msgstr "" "ενδεχόμενο να περιμένετε μέχρι να ολοκληρωθεί πριν από τον τερματισμό ή την " "επανεκκίνηση." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Κάνετε επανεκκίνηση" @@ -5463,6 +5412,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Τερματισμός τώρα" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5513,7 +5495,7 @@ msgstr "" "Πρόσβαση στη διεύθυνση URL {url} με διακομιστή μεσολάβησης {proxy} στο TCP " "{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5531,7 +5513,7 @@ msgstr "" "πελάτες Κουάσελ από ένα υπολογιστή ή ένα κινητό μπορούν να χρησιμοποιηθούν " "για τη σύνδεση και την αποσύνδεση από αυτό." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your υπολογιστή και κινητό είναι διαθέσιμοι." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "Πελάτης IRC" @@ -5555,7 +5537,7 @@ msgstr "Πελάτης IRC" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5575,7 +5557,7 @@ msgstr "" "clients/\">πελάτη . Το Radicale μπορεί να προσεγγιστεί από οποιονδήποτε " "χρήστη με {box_name} πιστοποιητικά." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5586,12 +5568,12 @@ msgstr "" "γεγονότων ή επαφών, το οποίο πρέπει να γίνει χρησιμοποιώντας ένα ξεχωριστό " "πελάτη." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Ημερολόγιο και βιβλίο διευθύνσεων" @@ -5670,7 +5652,7 @@ msgstr "" "κλικ στο κουμπί αναζήτηση σε λίστα με υπάρχοντα ημερολόγια και βιβλία " "διευθύνσεων." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Η διαμόρφωση των δικαιωμάτων πρόσβασης ενημερώθηκε" @@ -5771,7 +5753,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Διαβάστε και εγγραφείτε τροφοδοσίες ειδήσεων" @@ -5784,7 +5766,7 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5792,7 +5774,7 @@ msgstr "" "Το Samba επιτρέπει την κοινή χρήση αρχείων και φακέλων μεταξύ του Freedombox " "και άλλων υπολογιστών στο τοπικό σας δίκτυο." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5807,11 +5789,11 @@ msgstr "" "Υπάρχουν τρεις τύποι κοινόχρηστων αρχείων από τα οποία μπορείτε να " "επιλέξετε: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Ανοιχτό μέρισμα - ορατό σε όλους τους χρήστες του τοπικού δικτύου." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5819,7 +5801,7 @@ msgstr "" "Ομαδικό μέρισμα - ορατό μόνο σε χρήστες του Freedombox που είναι στην ομάδα " "Freedombox-share." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5827,15 +5809,15 @@ msgstr "" "Οικιακό μέρισμα - κάθε χρήστης στην ομάδα freedombox-share μπορεί να έχει το " "δικό του προσωπικό διαμέρισμα στο δίσκο." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Πρόσβαση στα ιδιωτικά μερίσματα" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 #, fuzzy #| msgid "Distributed File Storage" msgid "Network File Storage" @@ -5938,17 +5920,17 @@ msgstr "Όνομα μερίσματος" msgid "Action" msgstr "Ενέργεια" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "Freedombox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Aνοικτό μέρισμα" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Ομαδικό μέρισμα" @@ -5974,7 +5956,7 @@ msgstr "Το μέρισμα απενεργοποιήθηκε." msgid "Error disabling share: {error_message}" msgstr "Σφάλμα κατά την απενεργοποίηση του μερίσματος: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5983,7 +5965,7 @@ msgstr "" "ιδιωτικότητα. Μαζεύει και εμφανίζει αποτελέσματα από πολλαπλές μηχανές " "αναζήτησης." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5992,41 +5974,41 @@ msgstr "" "δημιουργία προφίλ χρήστη από τις μηχανές αναζήτησης. Δεν αποθηκεύει cookies " "από προεπιλογή." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Αναζήτηση στο διαδίκτυο" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Διαδικτυακή αναζήτηση" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Ασφαλής αναζήτηση" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Επιλέξτε το οικογενειακό φίλτρο που θα εφαρμοστεί στα αποτελέσματα " "αναζήτησης." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Μέτριο" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Αυστηρό" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Να επιτρέπεται δημόσια πρόσβαση" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Να επιτρέπεται η χρήση αυτής της εφαρμογής από οποιονδήποτε μπορεί να την " @@ -6213,7 +6195,7 @@ msgstr "Σελιδοδείκτες" msgid "Shaarlier" msgstr "Shaarli" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6223,7 +6205,7 @@ msgstr "" "σκοπό να προστατεύσει την κίνησή σας στο διαδίκτυο. Μπορεί να χρησιμοποιηθεί " "για να παρακάμψει το φιλτράρισμα στο Διαδίκτυο και τη λογοκρισία." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6237,7 +6219,7 @@ msgstr "" "διακομιστή μεσολάβησης και τα δεδομένα τους θα κρυπτογραφηθούν και θα " "αποσταλούν μέσω του διακομιστή shadowsocks." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6247,43 +6229,43 @@ msgstr "" "την εφαρμογή που επιθυμείτε στη διεύθυνση του freedomox http: // " "freedombox_address: 1080 /" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Διακομιστής μεσολάβησης τύπου socks5" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Συνιστάται" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Διακομιστής" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Όνομα διακομιστή ή διεύθυνση IP" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Αριθμός θύρας διακομιστή" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Κωδικός πρόσβασης που χρησιμοποιείται για την κρυπτογράφηση δεδομένων. " "Πρέπει να ταιριάζει με τον κωδικό πρόσβασης του διακομιστή." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" "Μέθοδος κρυπτογράφησης. Πρέπει να ταιριάζει με τη ρύθμιση στο διακομιστή." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6292,15 +6274,15 @@ msgstr "" "To Sharing σάς επιτρέπει να μοιράζεστε αρχεία και φακέλους στο {box_name} " "μέσω του διαδικτύου με επιλεγμένες ομάδες χρηστών." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Κοινή χρήση" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Όνομα του κοινόχρηστου στοιχείου" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6308,31 +6290,31 @@ msgstr "" "Μια αλφαριθμητική συμβολοσειρά (μικρά γράμματα) που προσδιορίζει με μοναδικό " "τρόπο ένα κοινόχρηστο στοιχείο. Παράδειγμα: πολυμέσα ." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Μονοπάτι που θα μοιραστείτε" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Μονοπάτι δίσκου σε αυτό το διακομιστή που σκοπέυετε να μοιραστείτε." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Μοιραστείτε δημόσια" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" "Κάνουν τα αρχεία σε αυτόν το φάκελο διαθέσιμα σε οποιονδήποτε διαθέτει το " "σύνδεσμο." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 #, fuzzy #| msgid "User groups that can read the files in the share" msgid "User groups that can read the files in the share:" msgstr "Ομάδες χρηστών που μπορούν να διαβάσουν τα αρχεία στο μέρισμα" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6340,11 +6322,11 @@ msgstr "" "Οι χρήστες των επιλεγμένων ομάδων χρηστών θα μπορούν να διαβάσουν τα αρχεία " "στο μέρισμα." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Υπάρχει ήδη ένα μέρισμα με αυτό το όνομα." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" "Τα μερίσματα θα πρέπει να είναι είτε δημόσια είτε να μοιράζονται με " @@ -6383,19 +6365,19 @@ msgstr "Το μέρισμα προστέθηκε." msgid "Add Share" msgstr "Προσθήκη μερίσματος" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Το μέρισμα ρυθμίστηκε." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Επεξεργασία μερίσματος" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Το μέρισμα διαγράφηκε." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6406,7 +6388,7 @@ msgstr "" "σε μια προηγουμένως γνωστή καλή κατάσταση σε περίπτωση ανεπιθύμητων αλλαγών " "στο σύστημα." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6417,7 +6399,7 @@ msgstr "" "και επίσης πριν και μετά από μια εγκατάσταση λογισμικού. Τα παλαιότερα " "στιγμιότυπα θα καθαρίζονται αυτόματα σύμφωνα με τις παρακάτω ρυθμίσεις." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for αντίγραφα ασφαλείας επειδή " "μπορούν να αποθηκευτούν μόνο στο ίδιο διαμέρισμα του δίσκου. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Στιγμιότυπα συστήματος αρχείων" @@ -6537,7 +6519,7 @@ msgstr "Ημερομηνία" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Διαγραφή στιγμιότυπων" @@ -6595,62 +6577,62 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Επαναφορά στο στιγμιότυπο #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Repository created." msgid "manually created" msgstr "Το αποθετήριο δημιουργήθηκε." -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Διαχείριση στιγμιότυπων" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Το στιγμιότυπο δημιουργήθηκε." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Η ρύθμιση παραμέτρων των στιγμιότυπων αποθήκευσης Ενημερώθηκε" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Σφάλμα ενέργειας: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Διαγράφηκαν επιλεγμένα στιγμιότυπα" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" "Το στιγμιότυπο χρησιμοποιείται αυτήν τη στιγμή. Παρακαλώ προσπαθήστε ξανά " "αργότερα." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Πραγματοποιήθηκε επαναφορά στο στιγμιότυπο #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" "Πρέπει να γίνει επανεκκίνηση του συστήματος για να ολοκληρωθεί η επαναφορά." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Επαναφορά σε στιγμιότυπο" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6663,7 +6645,7 @@ msgstr "" "αντιγράψει αρχεία ή να εκτελέσει άλλες υπηρεσίες χρησιμοποιώντας αυτές τις " "συνδέσεις." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Διακομιστής SSH" @@ -6702,14 +6684,6 @@ msgstr "Αλγόριθμος" msgid "Fingerprint" msgstr "Ψηφιακό αποτύπωμα" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "Έλεγχος ταυτότητας SSH με κωδικό πρόσβασης απενεργοποιήθηκε." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "Έλεγχος ταυτότητας SSH με κωδικό πρόσβασης ενεργοποιήθηκε." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Ενιαία είσοδος" @@ -6724,7 +6698,7 @@ msgstr "Σύνδεση" msgid "Logged out successfully." msgstr "Ο κωδικός πρόσβασης άλλαξε με επιτυχία." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6736,92 +6710,92 @@ msgstr "" "χρησιμοποιούνται προς το παρόν, να προσθέσετε και να αφαιρέσετε αφαιρούμενα " "μέσα, επεκτείνετε το root διαμέρισμα κλπ." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Χώρος Αποθήκευσης" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bytes" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Η ενέργεια απέτυχε." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Η ενέργεια ακυρώθηκε." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Η συσκευή είναι ήδη προς αφαίρεση." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "Η ενέργεια δεν υποστηρίζεται λόγω μη υποστήριξης προγραμματος οδηγού." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Η ενέργεια απέτυχε επειδή διήρκησε πολύ χρόνο." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" "Η ενέργεια θα ξυπνήσει ένα δίσκο που είναι σε μια βαθιά κατάσταση ύπνου." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Γίνεται προσπάθεια αφαίρεσης μιας συσκευής που είναι απασχολημένη." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Η ενέργια έχει ήδη ακυρωθεί." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Δεν έχετε εξουσιοδότηση για την εκτέλεση της συγκεκριμένης ενέργειας." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Η συσκευή έχει ήδη προστεθεί." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Η συσκευή δεν είναι τοποθετημένη." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Δεν έχετε εξουσιοδότηση για την εκτέλεση της συγκεκριμένης ενέργειας." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Η συσκευή έχει ήδη προστεθεί από άλλο χρήστη." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, fuzzy, no-python-format, python-brace-format #| msgid "" #| "Warning: Low space on system partition ({percent_used}% used, " @@ -6831,54 +6805,54 @@ msgstr "" "Προειδοποίηση: χαμηλός χώρος στο διαμέρισμα του συστήματος ({percent_used}% " "χρησιμοποιείται, {free_space} είναι ελεύθερος)." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Το όνομα καταλόγου δεν είναι έγκυρο." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Ο κατάλογος δεν υπάρχει." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Το μονοπάτι δεν είναι κατάλογος." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Ο κατάλογος δεν είναι αναγνώσιμος από τον χρήστη." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Ο κατάλογος δεν είναι εγγράψιμος από το χρήστη." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Κατάλογος" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Υποκατάλογος (προαιρετικό)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Κοινοποίηση" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Άλλος κατάλογος (Καθορίστε παρακάτω)" @@ -6915,7 +6889,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Επεκτείνετε το διαμέρισμα root" @@ -6936,30 +6910,30 @@ msgstr "" "προχωρήσετε. Μετά από αυτήν τηv ενέργεια, %(expandable_root_size)s του " "ελεύθερου χώρου θα είναι διαθέσιμο στο root διαμέρισμα." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Σφάλμα επέκτασης του διαμερίσματος: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Το διαμέρισμα επεκτάθηκε με επιτυχία." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} μπορεί να αποσυνδεθεί με ασφάλεια." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Η συσκευή μπορεί να αποσυνδεθεί με ασφάλεια." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Σφάλμα κατά την αφαίρεση της συσκευής: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6971,7 +6945,7 @@ msgstr "" "δημιουργία, η τροποποίηση ή η διαγραφή αρχείων σε μία συσκευή θα αναπαραχθεί " "αυτόματα σε όλες τις άλλες συσκευές που εκτελούν επίσης το Syncthing." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, fuzzy, python-brace-format #| msgid "" #| "Running Syncthing on {box_name} provides an extra synchronization point " @@ -6998,20 +6972,20 @@ msgstr "" "{box_name} είναι διαθέσιμη μόνο για χρήστες που ανήκουν στην ομάδα \"admin" "\" (διαχειριστών)." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Διαχειριστείτε την εφαρμογή Syncthing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Συγχρονισμός αρχείων" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7025,7 +6999,7 @@ msgstr "" "Project συνιστά να χρησιμοποιήσετε το πρόγραμμα περιήγησης διαδικτύου Tor." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, fuzzy, python-brace-format #| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." msgid "" @@ -7033,40 +7007,40 @@ msgid "" "TCP port 9050." msgstr "Μια θύρα Tor SOCKS είναι διαθέσιμη στη θύρα 9050 του %(box_name)s σας." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Υπηρεσία κρεμυδιού Tor" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor διακομιστής μεσολάβησης τύπου socks5" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Γέφυρα/μεσολαβητής Tor" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Θύρα μεσολαβητή Tor διαθέσιμη" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 μεταφορά καταχωρήθηκε" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 μεταφορά καταχωρήθηκε" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Πρόσβαση στη διεύθυνση URL {url} με tcp {kind} μέσω του Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Επιβεβαίωση χρήσης του Tor στο {url} στο προτόκολλο TCP {kind}" @@ -7189,13 +7163,13 @@ msgstr "Υπηρεσία κρεμμυδιού" msgid "Ports" msgstr "Θύρες" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Παρουσιάστηκε σφάλμα κατά τη ρύθμιση παραμέτρων." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -7257,7 +7231,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7267,7 +7241,7 @@ msgstr "" "σχεδιασμένος να επιτρέπει την ανάγνωση ειδήσεων από οποιαδήποτε τοποθεσία, " "ενώ δίνει την εντύπωση μιας πραγματικής εφαρμογής επιφάνειας εργασίας." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Tiny Tiny RSS can be accessed by any χρήστη με {box_name} πιστοποιητικά." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 #, fuzzy #| msgid "" #| "When using a mobile or desktop application for Tiny Tiny RSS, use the URL " @@ -7293,11 +7267,11 @@ msgstr "" "Tiny Tiny RSS, χρησιμοποιήστε τη διεύθυνση URL /tt-rss-app για τη σύνδεση." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Αναγνώστης ειδήσεων" @@ -7305,13 +7279,13 @@ msgstr "Αναγνώστης ειδήσεων" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Ελέγξτε και εφαρμόστε τις πιο πρόσφατες ενημερώσεις λογισμικού και ασφαλείας." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7319,8 +7293,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -7328,30 +7302,30 @@ msgstr "" msgid "Software Update" msgstr "Το μέρισμα διαγράφηκε." -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox Foundation" msgid "FreedomBox Updated" msgstr "Ίδρυμα FreedomBox" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution update started" msgstr "Oι αυτόματες ενημερώσεις απενεργοποιήθηκαν" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7539,50 +7513,50 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Oι αυτόματες ενημερώσεις ενεργοποιήθηκαν" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Σφάλμα κατά τη ρύθμιση των αυτόματων ενημερώσεων: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Oι αυτόματες ενημερώσεις ενεργοποιήθηκαν" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Oι αυτόματες ενημερώσεις απενεργοποιήθηκαν" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Distribution upgrade enabled" msgstr "Oι αυτόματες ενημερώσεις ενεργοποιήθηκαν" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution upgrade disabled" msgstr "Oι αυτόματες ενημερώσεις απενεργοποιήθηκαν" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Ξεκίνησε η διαδικασία αναβάθμισης." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Η εκκίνηση της αναβάθμισης απέτυχε." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Starting distribution upgrade test." msgstr "Oι αυτόματες ενημερώσεις ενεργοποιήθηκαν" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 #, fuzzy #| msgid "" #| "Create and managed user accounts. These accounts serve as centralized " @@ -7599,7 +7573,7 @@ msgstr "" "είναι μέρος μιας ομάδας για να εξουσιοδοτήσουν το χρήστη να αποκτήσει " "πρόσβαση στην εφαρμογή." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7611,15 +7585,15 @@ msgstr "" "σελίδα. Ωστόσο, μόνο οι χρήστες της ομάδας admin μπορούν να " "τροποποιήσουν τις εφαρμογές ή τις ρυθμίσεις του συστήματος." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Χρήστες και ομάδες" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Πρόσβαση σε όλες τις υπηρεσίες και τις ρυθμίσεις συστήματος" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Ελέγξτε την καταχώρηση LDAP \"{search_item}\"" @@ -7639,25 +7613,25 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 #, fuzzy #| msgid "Administrator Password" msgid "Authorization Password" msgstr "Κωδικός Πρόσβασης Διαχειριστή" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Show password" msgid "Invalid password." msgstr "Εμφάνιση κωδικού" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 #, fuzzy #| msgid "" #| "Select which services should be available to the new user. The user will " @@ -7679,13 +7653,13 @@ msgstr "" "υπηρεσίες. Μπορούν επίσης να συνδεθούν στο σύστημα μέσω του SSH και να έχουν " "δικαιώματα διαχειριστή (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "Η δημιουργία χρήστη LDAP απέτυχε." -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" @@ -7706,43 +7680,43 @@ msgstr "" "Μπορείτε να εισαγάγετε πολλαπλά κλειδιά, ένα σε κάθε γραμμή. Οι κενές " "γραμμές και οι γραμμές που ξεκινούν με # θα αγνοηθούν." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Η μετονομασία του χρήστη LDAP απέτυχε." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Απέτυχε η κατάργηση του χρήστη από την ομάδα." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Απέτυχε η προσθήκη χρήστη στην ομάδα." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Δεν ήταν δυνατό να προστεθούν τα κλειδιά SSH." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Απέτυχε η αλλαγή της κατάστασης χρήστη." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Η αλλαγή του κωδικού πρόσβασης χρήστη LDAP απέτυχε." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "Αποτυχία προσθήκης νέου χρήστη στην ομάδα διαχειριστών." -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, fuzzy, python-brace-format #| msgid "Failed to restrict console access." msgid "Failed to restrict console access: {error}" msgstr "Απέτυχε ο περιορισμός της πρόσβασης στην κονσόλα." -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Ο λογαριασμός χρήστη δημιουργήθηκε, τώρα είστε συνδεδεμένοι" @@ -7759,12 +7733,12 @@ msgstr "Αποθήκευση κωδικού πρόσβασης" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Δημιουργία χρήστη" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Διαγραφή χρήστη" @@ -7810,17 +7784,17 @@ msgid "The following administrator accounts exist in the system." msgstr "Δεν είναι δυνατή η διαγραφή του μοναδικού διαχειριστή στο σύστημα." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Χρήστες" @@ -7854,34 +7828,34 @@ msgstr "" msgid "Save Changes" msgstr "Αποθήκευση αλλαγών" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Ο χρήστης %(username)s δημιουργήθηκε." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "O χρήστης %(username)s ενημερώθηκε." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Επεξεργασία χρήστη" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Ο χρήστης {user} διαγράφηκε." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Η διαγραφή του χρήστη LDAP απέτυχε." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Αλλαγή κωδικού πρόσβασης" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Ο κωδικός πρόσβασης άλλαξε με επιτυχία." @@ -8254,7 +8228,7 @@ msgstr "Διαγραφή σύνδεσης" msgid "Server deleted." msgstr "Το μέρισμα διαγράφηκε." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8263,7 +8237,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8272,28 +8246,28 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 #, fuzzy #| msgid "Address" msgid "WordPress" msgstr "Διεύθυνση" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Wiki and Blog" msgid "Website and Blog" @@ -8311,7 +8285,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8324,7 +8298,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8332,11 +8306,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -8388,116 +8362,110 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing Backups" -msgid "Error running apt-get" -msgstr "Υπάρχοντα αντίγραφα ασφαλείας" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "Εγκαθίσταται" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "Λήψη" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "Αλλαγή μέσου" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "αρχείο ρυθμίσεων: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Εγκαταστήσετε Εφαρμογές" -#: plinth/setup.py:42 +#: plinth/setup.py:43 #, fuzzy #| msgid "Updating..." msgid "Updating app" msgstr "Eνημερώνεται..." -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Η εφαρμογή εγκαταστάθηκε." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Τελευταία ενημέρωση" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Εγκαταστήσετε Εφαρμογές" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Η εφαρμογή εγκαταστάθηκε." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -8570,53 +8538,54 @@ msgstr "Εγκατάσταση" msgid "Service %(service_name)s is not running." msgstr "Η υπηρεσία %(service_name)s δεν εκτελείται." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Βασική λειτουργικότητα και σελίδα ιστού για το %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Κεντρική σελίδα" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Κεντρική σελίδα" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Εφαρμογές" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Εφαρμογές" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Σύστημα" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Σύστημα" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Αλλαγή κωδικού πρόσβασης" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "ΤΕΡΜΑΤΙΣΜΟΣ ΛΕΙΤΟΥΡΓΙΑΣ" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Αποσύνδεση" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Επιλογή γλώσσας" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Σύνδεση" @@ -8917,6 +8886,48 @@ msgstr "" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Ενεργοποίηση DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "" +#~ "Ενεργοποίηση επεκτάσεων ασφαλείας για διακομιστές ονομάτων διαδικτύου " +#~ "(DNS)" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "To πρόγραμμα τείχους προστασίας δεν εκτελείται. Παρακαλείστε να το " +#~ "τρέξετε. Το τείχος προστασίας εμφανίζεται ενεργοποιημένο από προεπιλογή " +#~ "στο %(box_name)s. Σε οποιοδήποτε σύστημα που βασίζεται στο Debian (όπως " +#~ "το %(box_name)s) μπορείτε να το εκτελέσετε χρησιμοποιώντας την εντολή ' " +#~ "service firewalld start ' ή σε περίπτωση ενός συστήματος με systemd ' " +#~ "systemctl start firewalld '." + +#, fuzzy +#~| msgid "Moderate" +#~ msgid "Migrate" +#~ msgstr "Μέτριο" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "Έλεγχος ταυτότητας SSH με κωδικό πρόσβασης απενεργοποιήθηκε." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Έλεγχος ταυτότητας SSH με κωδικό πρόσβασης ενεργοποιήθηκε." + +#, fuzzy +#~| msgid "Existing Backups" +#~ msgid "Error running apt-get" +#~ msgstr "Υπάρχοντα αντίγραφα ασφαλείας" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Βασική λειτουργικότητα και σελίδα ιστού για το %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Συνδέσεις δικτύου" diff --git a/plinth/locale/es/LC_MESSAGES/django.po b/plinth/locale/es/LC_MESSAGES/django.po index 3ad209ea4..335e4cc70 100644 --- a/plinth/locale/es/LC_MESSAGES/django.po +++ b/plinth/locale/es/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Spanish calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1052,23 +1045,23 @@ msgstr "" "Solo los usuarios del grupo calibre podrán acceder a la app. Todos " "los usuarios con acceso pueden usar todas las bibliotecas." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Usar bibliotecas Calibre" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "Calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Biblioteca de libros electrónicos" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Nombre de la nueva biblioteca" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1076,7 +1069,7 @@ msgstr "" "Solo letras sin tilde, números, punto y guiones (- ó _), sin espacios, ni Ñ, " "ni Ç. Ejemplo: Mi_biblioteca_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Ya existe una biblioteca con este nombre." @@ -1124,20 +1117,20 @@ msgstr "Ir a biblioteca %(library)s" msgid "Delete library %(library)s" msgstr "Eliminar biblioteca %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Biblioteca creada." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Ha habido un error al crear la biblioteca." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} eliminado." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "No se pudo eliminar {name}: {error}" @@ -1185,7 +1178,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Administración del servidor" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1193,18 +1186,18 @@ msgstr "" "Opciones de configuración general como el nombre del host, el del dominio, " "la página de inicio del servidor web, etc." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Configuración general" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Configurar" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1322,47 +1315,47 @@ msgstr "" "Los registros de ejecución contienen información de quién accedió al sistema " "y detalles para depuración de varios servicios" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Error al definir el nombre de anfitrión: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Asignar nombre de anfitrión" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Error al establecer nombre de dominio: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Asignar nombre de dominio" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Error al configurar la página de inicio del servidor web: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Página de inicio del servidor web configurada" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Error al cambiar al modo avanzado: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Mostrando aplicaciones y funciones avanzadas" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Ocultando aplicaciones y funciones avanzadas" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1374,7 +1367,7 @@ msgstr "" "SIP y de otros tipos pueden usarlo para establecer llamadas entre partes que " "no tienen otra alternativa disponible." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ejabberd tienen que configurarse con los detalles que se " "proporcionan aquí." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "Asistente VoIP" @@ -1447,11 +1440,11 @@ msgstr "Error al definir zona horaria: {exception}" msgid "Time zone set" msgstr "Zona horaria asignada" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge es un cliente BitTorrent con interfaz web." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1459,16 +1452,16 @@ msgstr "" "La clave de acceso por defecto es 'deluge' pero es muy recomendable que nada " "más activar el servicio acceda al mismo y la cambie." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Descargar archivos usando aplicaciones BitTorrent" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Cliente web de BitTorrent" @@ -1595,7 +1588,7 @@ msgstr "Resultado" msgid "Diagnostic Test" msgstr "Test de diagnóstico" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1606,7 +1599,7 @@ msgstr "" "24h) será muy difícil para los demás encontrarle en Internet. Este servicio " "permitirá a otros encontrar los servicios que ofrece {box_name}." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1623,7 +1616,7 @@ msgstr "" "asigna su nombre DNS a esta nueva IP de forma que cualquiera que pida su " "nombre DNS obtendrá la dirección IP actualizada." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1636,11 +1629,11 @@ msgstr "" "de actualización en freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Cliente de DNS dinámico" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Nombre de dominio dinámico" @@ -1767,7 +1760,7 @@ msgstr "Este campo es obligatorio." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1822,7 +1815,7 @@ msgstr "El Servidor rechazo la conexión" msgid "Already up-to-date" msgstr "Ya Estaba Actualizada" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1830,7 +1823,7 @@ msgstr "" "XMPP es un protocolo de comunicación abierto y estándar. Puede ejecutar y " "configurar su servidor XMPP (ejabberd) aquí." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientcliente XMPP. Cuando se activa, ejabberd está disponible para " "cualquier usuario con acceso a {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn o configurar un servidor " "externo." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Servidor de Chat" @@ -1979,7 +1972,7 @@ msgstr "" "será parecida a username@%(domainname)s. Puede configurar su dominio " "en la página de sistema Configurar." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1990,7 +1983,7 @@ msgstr "" "Dovecot permite que los clientes de correo electrónico accedan a su buzón " "mediante IMAP y POP3. Rspamd se ocupa del spam." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2002,7 +1995,7 @@ msgstr "" "proveedores de internet también restringen el correo saliente. Algunos " "levantan la restricción a demanda. Más información en la página del manual." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2017,7 +2010,7 @@ msgstr "" "a su dirección de correo electrónico. Los alias necesarios como \"postmaster" "\" se crean automáticamente apuntando al primer usuario administrador." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2025,7 +2018,7 @@ msgstr "" "Roundcube app proporciona un " "interfaz web para que los usuarios accedan a correo electrónico." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2156,7 +2149,7 @@ msgstr "Puerto" msgid "Host/Target/Value" msgstr "Host/Objetivo/Valor" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2167,7 +2160,7 @@ msgstr "" "de su {box_name}. Mantenerlo activado y correctamente configurado reduce el " "riesgo de amenazas de seguridad desde Internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Cortafuegos" @@ -2187,52 +2180,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Puerto {name} ({details}) no disponible para redes externas" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"El servicio firewall no se está ejecutando. Por favor actívelo. El firewall " -"viene activado por defecto en su %(box_name)s. En cualquier sistema basado " -"en Debian (como %(box_name)s) puede activarlo con 'service firewalld start' " -"o si su sistema emplea systemd 'systemctl start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Servicio/Puerto" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Activado" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Desactivado" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Permitido" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Permitido (solo interno)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Permitido (solo externo)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Bloqueado" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2242,13 +2222,13 @@ msgstr "" "se autoriza en el firewall, y cuando lo desactiva también se desactiva en el " "firewall." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Avanzado" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2303,7 +2283,7 @@ msgstr "Iniciar configuración" msgid "Setup Complete" msgstr "Configuración completada" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2321,7 +2301,7 @@ msgstr "" "cliente Git de línea de comandos o múltiples clientes gráficos. Y puedes " "compartir tu código con gente de todo el mundo." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2329,68 +2309,68 @@ msgstr "" "Para aprender más acerca de cómo usar Git visita el tutorial de Git." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Acceso de lectura y escritura para repositorios Git" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Alojamiento simple para Git" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "URL de repositorio no válida." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Nombre de repositorio no válido." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Nombre de un nuevo repositorio o URL para importar un repositorio existente." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Descripción del repositorio" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Opcional, para mostrar en Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Nombre del dueño del repositorio" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Repositorio privado" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Permitir acceder a este repositorio sólo a usuarios autorizados." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Ya existe un repositorio con este nombre." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Nombre del repositorio" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "Una cadena alfanumérica que identifica unívocamente un repositorio." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Rama por omisión" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb muestra esta rama por omisión." @@ -2434,19 +2414,19 @@ msgstr "Borrar Repositorio Git %(name)s" msgid "Delete this repository permanently?" msgstr "¿Eliminar este repositorio definitivamente?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Repositorio creado." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Ha habido un error al crear el repositorio." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Repositorio editado." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Editar repositorio" @@ -2808,7 +2788,7 @@ msgstr "Acerca de {box_name}" msgid "{box_name} Manual" msgstr "Manual de {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2820,7 +2800,7 @@ msgstr "" "anonimato al enviar trafico cifrado a través de una red mantenida por " "voluntarios alrededor del mundo." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2828,7 +2808,7 @@ msgstr "" "Para ampliar información sobre I2P visite el sitio web del proyecto." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2836,19 +2816,19 @@ msgstr "" "La primer visita a la interfaz web provista iniciará el proceso de " "configuración." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Administrar la aplicación I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Red anónima" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "Proxy I2P" @@ -2894,7 +2874,7 @@ msgstr "" "red par-a-par. Descarga los archivos al agregar los torrents o crea un nuevo " "torrent para compartir un archivo." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2904,7 +2884,7 @@ msgstr "" "de marcado, Markdown incluido, y funcionalidades comunes de los blogs tal " "como comentarios o fuentes RSS." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2918,15 +2898,15 @@ msgstr "" "\"{users_url}\">configuración de usuarios puede modificar estos permisos " "o añadir nuevos usuarios." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki y Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Aplicaciones wiki para ver y editar" @@ -2982,41 +2962,41 @@ msgstr "" "Esta acción borrará todas las entradas, páginas y comentarios incluido el " "historial. ¿Eliminar este wiki o blog definitivamente?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Wiki {name} creado." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "No se pudo crear el wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Blog {name} creado." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "No se pudo crear el blog: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} eliminado." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "No se pudo eliminar {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted es un servidor para Gobby, un editor de texto colaborativo." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3028,11 +3008,11 @@ msgstr "" "seleccione \"Conectar al servidor\" e introduzca el nombre de dominio de su " "{box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Servidor Gobby" @@ -3080,7 +3060,7 @@ msgstr "Sala de vídeo Janus" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Información de licencia de JavaScript" @@ -3100,7 +3080,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Cliente de Chat" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3115,7 +3095,7 @@ msgstr "" "mostrándose a sí mismo como propietario de un dominio a Let's Encrypt, " "autoridad de certificación (CA)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3128,15 +3108,15 @@ msgstr "" "letsencrypt.org/repository/\">Acuerdo de suscripción de Let's Encrypt " "antes de usar este servicio." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Certificados" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "No puedo probar: No hay dominios configurados." @@ -3201,7 +3181,7 @@ msgstr "" "No se ha configurado ningún dominio. Configure " "alguno para poder asignarle un certificado." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3210,34 +3190,34 @@ msgstr "" "El certificado para el dominio {domain} ha sido revocado con éxito. " "Necesitará unos momentos para tener efecto." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Falló la revocación del certificado para el dominio {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Se ha obtenido con éxito el certificado para el dominio {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Falló la obtención del certificado para el dominio {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "El certificado para el dominio {domain} ha sido eliminado con éxito" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Falló la eliminación del certificado para el dominio {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3254,7 +3234,7 @@ msgstr "" "funcionar. La federación de los servidores permite que las/os usuarias/os de " "un servidor Matrix contacten con los de otro servidor." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3264,7 +3244,7 @@ msgstr "" "Instalar la app Coturn o configurar un servidor " "externo." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3371,7 +3351,7 @@ msgstr "" "TLS válido. Vaya a Let's Encrypt para " "obtener uno." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3383,7 +3363,7 @@ msgstr "" "colaboración. Puede usar MediaWiki para alojar un sitio tipo wiki, tomar " "notas o colaborar en proyectos con otras personas." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3397,7 +3377,7 @@ msgstr "" "MediaWiki en la página Special:CreateAccount." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3405,12 +3385,12 @@ msgstr "" "Cualquiera con acceso a este wiki puede leerlo, pero solo quien se " "autentique en el sistema podrá modificar el contenido." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3494,35 +3474,35 @@ msgid "Password update failed. Please choose a stronger password" msgstr "" "Falló la actualización de la contraseña. Use otra contraseña más fuerte" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Habilitado el registro público" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Inhabilitado el registro público" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Activado el modo privado" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Desactivado el modo privado" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Tema por defecto cambiado" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Nombre de dominio actualizado" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Nombre de sitio actulizado" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3535,11 +3515,11 @@ msgstr "" "defecto (30000). Para acceder al servidor necesitará un Cliente Minetest." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Sandbox de bloques" @@ -3592,7 +3572,7 @@ msgstr "" msgid "Address" msgstr "Dirección" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3776,7 +3756,7 @@ msgstr "Intérprete de órdenes seguro" msgid "Services" msgstr "Servicios" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3784,7 +3764,7 @@ msgstr "" "Configurar dispositivos de red. Conectar con Internet mediante Ethernet, Wi-" "Fi o PPPoE. Compartir esa conexión con otros dispositivos de la red." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3792,7 +3772,7 @@ msgstr "" "Los dispositivos administrados mediante otros métodos quizá no estén " "disponibles para configurarse aquí." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Redes" @@ -4222,7 +4202,7 @@ msgstr "Editar conexión" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Editar" @@ -4327,7 +4307,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Método" @@ -4343,7 +4323,7 @@ msgstr "Servidor DNS" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Por defecto" @@ -4356,7 +4336,7 @@ msgid "This connection is not active." msgstr "Esta conexión no está activa." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Protección" @@ -4939,7 +4919,7 @@ msgstr "Conexión {name} eliminada." msgid "Failed to delete connection: Connection not found." msgstr "Ha fallado la eliminación de la conexión: no se encontró." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4956,20 +4936,20 @@ msgstr "" "forma privada. También puede acceder a Internet a través de su {box_name} " "para añadir protección y anonimato." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Conectar a servicios VPN" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Red privada virtual" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4980,58 +4960,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Migrar a crioptografía ECC (basada en curvas elípticas)" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Actualmemte tu instalación OpenVPN está usando RSA. Cambiar a Criptografía " -"de Curva Elíptica (ECC) mejora la velocidad y seguridad al establecer " -"conexiones. Esta operación es irreversible. En la mayoría de computadores " -"monoplaca debería tardar escasos minutos." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Todas las instalaciones nuevas de OpenVPN sobre %(box_name)s usarán ECC de " -"serie. Recomendamos migrar cuanto antes." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Aviso: Esta operación invalidará los perfiles de cliente existentes. " -"Todos los usuarios de OpenVPN en %(box_name)s tienen que descargar sus " -"perfiles nuevos. Para conectar con este servidor tendrán que usar clientes " -"OpenVPN compatibles con ECC." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Migrar" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Perfil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Para conectar a la VPN de %(box_name)s necesita descargar un perfil y " @@ -5040,18 +4983,19 @@ msgstr "" "\"Aprender más...\" para información sobre los clientes recomendados y cómo " "configurarlos." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "El perfil es específico de cada usuaria/o de %(box_name)s. Manténgalo en " "secreto." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Descargar mi perfil" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5064,18 +5008,18 @@ msgstr "" "servicios de su {box_name} no son accesibles desde Internet. Esto incluye " "las siguientes situaciones:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} está detrás de un firewall restringido." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} está conectado a un router (inalámbrico) que usted no controla." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5083,7 +5027,7 @@ msgstr "" "Su proveedor de servicio no le da una dirección IP externa y, por el " "contrario, le facilita conexión a Internet a través de un NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5091,11 +5035,11 @@ msgstr "" "Su proveedor de servicios no le da una dirección IP estática por lo que su " "IP cambia cada vez que se conecta a Internet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Su proveedor de servicios limita las conexiones entrantes." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5108,23 +5052,23 @@ msgstr "" "de servicios pagekite, por ejemplo pagekite." "net. En el futuro será posible usar su amigable {box_name} para esto." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Visibilidad pública" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "Dominio PageKite" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Dominio del servidor" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5132,31 +5076,31 @@ msgstr "" "Seleccione su servidor pagekite. Elija \"pagekite.net\" para usar el " "servidor pagekite por defecto." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Puerto del servidor" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Puerto de su servidor pagekite (por defecto es 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Nombre Kite" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Ejemplo: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Nombre de kite inválido" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Clave para Kite" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5164,35 +5108,35 @@ msgstr "" "Una clave asociada al Kite o la clave por defecto para su cuenta si no se " "especifica ninguna." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protocolo" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "puerto externo (frontend)" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "puerto interno (freedombox)" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Activar subdominios" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Servicio personalizado eliminado" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Este servicio ya está disponible como servicio estándar." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Servicio personalizado añadido" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Este servicio ya existe" @@ -5230,29 +5174,29 @@ msgstr "" "Por ejemplo, se sabe que HTTPS en un puerto distinto de 443 causará " "problemas." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Servidor Web (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "El sitio estará disponible en http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Servidor web seguro (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "El sitio estará disponible en https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Intérprete de órdenes seguro (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5303,8 +5247,8 @@ msgstr "" "Otra instalación o actualización está actualmente en ejecución. Por favor " "espere unos momentos antes de apagar o reiniciar." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Reiniciar" @@ -5354,6 +5298,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Apagar ahora" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5395,7 +5372,7 @@ msgstr "Proxy Web" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Acceso a {url} con proxy {proxy} en tcp {kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5412,7 +5389,7 @@ msgstr "" "conectado de forma que distintos clientes Quassel pueden conectarse y " "desconectarse de este servidor desde un ordenador de escritorio o un móvil." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your escritorio y móvil." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "Cliente IRC" @@ -5436,7 +5413,7 @@ msgstr "Cliente IRC" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5451,7 +5428,7 @@ msgstr "" "supported-clients\">aplicación cliente soportada. Cualquier persona " "autenticada en {box_name} puede acceder a Radicale." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5461,12 +5438,12 @@ msgstr "" "de nuevos calendarios y agendas. No soporta añadir eventos o contactos, que " "debe hacerse usando un cliente separado." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Calendario y Contactos" @@ -5540,7 +5517,7 @@ msgstr "" "freedombox>) y su nombre de usuario. Pulsando en el botón de búsqueda le " "mostrará un listado de los calendarios y agendas existentes." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Configuración de derechos de acceso actualizada" @@ -5632,7 +5609,7 @@ msgstr "" "seguir varios sitios web. Habilita la autenticación y usa tus credenciales " "de {box_name} al añadir un feed." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Leer y suscribirse a nuevos agregadores" @@ -5645,7 +5622,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "Generador de feeds RSS" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5653,7 +5630,7 @@ msgstr "" "Samba permite compartir archivos y carpetas entre FreedomBox y otras " "computadoras en su red local." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5666,11 +5643,11 @@ msgstr "" "la dirección \\\\{hostname} (en Windows) o smb://{hostname}.local (en Linux " "y Mac). Puede elegir entre tres tipos para compartir: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Compartir en abierto - accesible para todo el mundo en su red local." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5678,7 +5655,7 @@ msgstr "" "Compartir en grupo - accesible solo para las personas que estén en el grupo " "freedombox-share." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5686,15 +5663,15 @@ msgstr "" "Compartir en mi cuenta - todos los miembros del grupo freedombox-share " "disponen de un espacio privado propio." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Acceso a los elementos compartidos privados" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Sistema de archivos en red" @@ -5783,15 +5760,15 @@ msgstr "Nombre de compartición" msgid "Action" msgstr "Acción" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "Disco de sistema de FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Compartir en abierto" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Compartir con grupo" @@ -5817,7 +5794,7 @@ msgstr "Compartición desactivada." msgid "Error disabling share: {error_message}" msgstr "Error al desactivar compartición: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5825,7 +5802,7 @@ msgstr "" "Searx es un motor de búsqueda en Internet que respeta la privacidad. Recoge " "y muestra los resultados de múltiples buscadores." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5833,41 +5810,41 @@ msgstr "" "Searx se puede usar para evitar el rastreo y la creación de perfiles que " "realizan los buscadores. Por defecto no almacena cookies." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Buscar en la web" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Buscador web" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Búsqueda segura" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Seleccione la familia de filtros que se aplicarán por defecto a los " "resultados de su búsqueda." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Moderado" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Estricto" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Permitir acceso público" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Permitir que esta aplicación la use cualquiera que pueda acceder a ella." @@ -6048,7 +6025,7 @@ msgstr "Marcadores" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6058,7 +6035,7 @@ msgstr "" "tráfico en Internet. Se puede usar para eludir el filtrado o la censura de " "Internet." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6071,7 +6048,7 @@ msgstr "" "Los dispositivos locales pueden conectarse a este proxy y la información se " "enviará cifrada a través del servidor Shadowsocks." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6079,40 +6056,40 @@ msgstr "" "Para usar Shadowsocks una vez configurado debe indicar la URL del proxy en " "su dispositivo, navegador o aplicación como http://freedombox_address:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Proxy Socks5" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Recomendado" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Servidor" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Nombre del servidor o dirección IP" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Número de puerto del servidor" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "Clave para cifrar los datos. Debe coincidir con la clave del servidor." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Método de cifrado. Debe coincidir con la configuración del servidor." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6121,15 +6098,15 @@ msgstr "" "Permite compartir a través de la web archivos y carpetas en su {box_name} " "con otras personas." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Compartir" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Nombre de la compartición" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6137,29 +6114,29 @@ msgstr "" "Una cadena alfa-numérica en minúsculas que identifica de forma unívoca la " "compartición. Ejemplo: media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Ruta de acceso a la compartición" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" "Ruta de acceso en el disco de este servidor a la carpeta que pretende " "compartir." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Carpeta pública" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Dar acceso a los archivos de esta carpeta a quien tenga el enlace." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Grupos de usuarias/os que pueden leer los archivos compartidos:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6167,11 +6144,11 @@ msgstr "" "Los usuarios de los grupos seleccionados podrán leer los archivos " "compartidos." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Ya existe una compartición con este nombre." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" "Las carpetas compartidas deben ser públicas o estar compartidas con al menos " @@ -6210,19 +6187,19 @@ msgstr "Compartición añadida." msgid "Add Share" msgstr "Añadir compartición" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Compartición editada." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Editar compartición" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Compartición eliminada." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6232,7 +6209,7 @@ msgstr "" "btrfs. Éstas pueden emplearse para recuperar el sistema a un estado anterior " "correcto en caso de cambios no deseados." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6244,7 +6221,7 @@ msgstr "" "instantáneas más antiguas se eliminarán automáticamente según la siguiente " "configuración." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for las copias de seguridad ya que se almacenan en la " "misma partición. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Instantáneas" @@ -6359,7 +6336,7 @@ msgstr "Fecha" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Eliminar instantáneas" @@ -6412,58 +6389,58 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Restaurar a instantánea %(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "creada a mano" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "linea de tiempo" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "APT" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Gestionar instantáneas" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Instantánea creada." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Configuración de instantáneas actualizada" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Acción de error: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Las instantáneas seleccionadas fueron eliminadas" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" "La instantánea se está usando actualmente. Inténtelo de nuevo más tarde." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Sistema restaurado a la instantánea {number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Debe reiniciar el sistema para completar la restauración." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Restaurar a instantánea" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6475,7 +6452,7 @@ msgstr "" "de administración, copiar archivos o ejecutar otros servicios a través de " "esas conexiones." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Servidor de intérprete de órdenes seguro (SSH)" @@ -6513,14 +6490,6 @@ msgstr "Algoritmo" msgid "Fingerprint" msgstr "Huella digital" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "Acceso SSH con clave desactivado." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "Acceso SSH con clave activado." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Inicio de sesión único" @@ -6533,7 +6502,7 @@ msgstr "Inicio de sesión" msgid "Logged out successfully." msgstr "Desconectado con éxito." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6544,106 +6513,106 @@ msgstr "" "{box_name}. Puede ver el medio de almacenamiento que está usando, montar y " "desmontar medios extraíbles, ampliar la partición raíz, etc." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Almacenamiento" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bytes" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Falló la operación." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Se ha cancelado la operación." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "El dispositivo ya se está desmontando." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "No se soporta esta operación por falta de un driver o herramienta." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "La operación agotó el tiempo." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "La operación podría activar un disco que está en estado de reposo." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Tratando de desmontar un dispositivo ocupado." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Ya se ha cancelado la operación." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "No tiene autorización para la operación solicitada." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "El dispositivo ya está montado." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "El dispositivo no está montado." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "La operación solicitada no está permitida." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "El dispositivo está ya montado por otro usuario." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Poco espacio en la partición del sistema: {percent_used}% usado, " "{free_space} libre." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Poco espacio en disco" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Fallo de disco inminente" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6652,39 +6621,39 @@ msgstr "" "El disco {id} informa que es probable que falle en breve. Copie los datos " "mientras pueda y reemplace el disco." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Nombre de carpeta no válido." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "La carpeta no existe." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "No es una carpeta." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "El usuario no tiene permiso de lectura en esta carpeta." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "El usuario no tiene permiso de escritura en esta carpeta." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Carpeta" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Subcarpeta (opcional)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Compartir" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Otra carpeta (especifique más abajo)" @@ -6721,7 +6690,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Ampliar partición raíz" @@ -6745,30 +6714,30 @@ msgstr "" "operación su partición raíz dispondrá de %(expandable_root_size)s espacio " "libre adicional." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Error al ampliar partición: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Partición ampliada con éxito." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "Ya puede desconectar {drive_vendor} {drive_model} con seguridad." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "El dispositivo ya se puede desconectar con seguridad." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Error al expulsar el dispositivo: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6780,7 +6749,7 @@ msgstr "" "modificación o borrado de archivos en uno de los dispositivos se replica " "automáticamente en todos los demás que también estén ejecutando Syncthing." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6799,20 +6768,20 @@ msgstr "" "interfaz web en {box_name} solo está disponible para quienes pertenezcan a " "los grupos \"admin\" o \"syncthing-access\"." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Administrar Syncthing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Sincronización de archivos" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6826,7 +6795,7 @@ msgstr "" "download/download-easy.html.en\">Navegador Tor para tener la mejor " "protección cuando navega por la red." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6835,40 +6804,40 @@ msgstr "" "Un puerto SOCKS de Tor está disponible para redes internas en su {box_name} " "en el puerto TCP 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Servicio Tor Onion" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Proxy Socks para Tor" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Puente de retransmisión Tor" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Puerto de servidor Tor disponible" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Transporte Obfs3 registrado" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Transporte Obfs4 registrado" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Acceso a URL {url} sobre tcp {kind} vía Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Confirmar uso de Tor en {url} sobre tcp {kind}" @@ -6989,13 +6958,13 @@ msgstr "Servicio Onion" msgid "Ports" msgstr "Puertos" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Ha habido un error en la configuración." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error updating app: {error}" msgid "Error configuring app: {error}" @@ -7059,7 +7028,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7069,7 +7038,7 @@ msgstr "" "publicar desde cualquier lugar, a la vez que mantiene un aspecto de " "aplicación de escritorio en la medida de lo posible." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7078,7 +7047,7 @@ msgstr "" "Cuando está activado, Tiny Tiny RSS estará disponible para cualquier persona perteneciente a un grupo de lector de feeds." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7086,11 +7055,11 @@ msgstr "" "Cuando emplee una aplicación de móvil o de escritorio para Tiny Tiny RSS, " "use la URL /tt-rss-app para conectar." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Lector de noticias" @@ -7098,13 +7067,13 @@ msgstr "Lector de noticias" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Bifurcación)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Buscar y aplicar las últimas actualizaciones del software y de seguridad." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7118,22 +7087,22 @@ msgstr "" "tiempo. Si se decide retrasar el reinicio del sistema, éste se hará de forma " "automática a las 02:00 h." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Actualización de software (Update)" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox actualizado" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "No se pudo iniciar la actualización de la distribución" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7144,11 +7113,11 @@ msgstr "" "libres. Si está habilitada, la actualización de la distribución se " "reintentará tras 24h ." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Iniciada la actualización de la distribución" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7329,46 +7298,46 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Actualización automática de distibución activada" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Error al configurar las actualizaciones desatendidas: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Actualizaciones automáticas activadas" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Actualizaciones automáticas desactivadas" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Actualización automática de distibución activada" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Actualización automática de distibución desactivada" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Proceso de actualización iniciado." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "No se ha podido iniciar la actualización." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Las actualizaciones funcionales frecuentes están activadas." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Distribution upgrade enabled" msgid "Starting distribution upgrade test." msgstr "Actualización automática de distibución activada" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7379,7 +7348,7 @@ msgstr "" "requieren que además la cuenta de usuario conste en un grupo para " "autorizarles a acceder." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7391,15 +7360,15 @@ msgstr "" "sólo los usuarios del grupo admin pueden cambiar configuraciones de " "apps o del sistema." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Usuarias/os y grupos" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Acceso a todos los servicios y configuraciones del sistema" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Comprobar la entrada LDAP \"{search_item}\"" @@ -7417,11 +7386,11 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "Obligatorio. Hasta 150 caracteres. Solo letras, números y @/./-/_ ." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Contraseña de autorización" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7429,11 +7398,11 @@ msgstr "" "Introduce la contraseña del usuario \"{user}\" para autorizar modificaciones " "en la cuenta." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Contraseña no válida." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7448,12 +7417,12 @@ msgstr "" "servicios, también podrán acceder al sistema por SSH con privilegios de " "administración (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Ha fallado la creación de usuaria/o LDAP: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Ha fallado añadir usuaria/o nuevo al grupo {group}: {error}" @@ -7472,41 +7441,41 @@ msgstr "" "de una clave. Puede introducir más de una clave, cada una en una línea. Las " "líneas en blanco y las que empiecen por # se ignorarán." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Ha fallado renombrar al o la usuaria LDAP." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Ha fallado la eliminación del o de la usuaria del grupo." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Ha fallado añadir al o la usuaria al grupo." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "No es posible configurar las claves SSH." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Ha fallado al cambiar el estado del usuario." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Ha fallado cambiar la clave del o de la usuaria LDAP." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Ha fallado añadir usuaria/o nueva/o al grupo admin: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Falló al restringir el acceso a la consola: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Creada cuenta de usuaria/o, ya está usted en el sistema" @@ -7523,12 +7492,12 @@ msgstr "Guardar clave de acceso" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Crear usuaria/o" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Eliminar usuaria/o" @@ -7569,13 +7538,19 @@ msgid "The following administrator accounts exist in the system." msgstr "La siguiente cuenta de administración existe en el sistema." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Si ya hay una cuenta usable con %(box_name)s sáltese este paso: Si no, " "elimine estas cuentas desde la línea de órdenes y refresque la página para " @@ -7584,7 +7559,7 @@ msgstr "" "la línea de órdenes." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Usuarias/os" @@ -7617,34 +7592,34 @@ msgstr "" msgid "Save Changes" msgstr "Guardar cambios" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Se ha creado el o la usuaria %(username)s." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "El o la usuaria %(username)s se ha actualizado." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Editar usuario" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "El o la usuaria {user} se ha eliminado." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Ha fallado la eliminación del o de la usuaria LDAP." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Cambiar clave de acceso" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Clave de acceso cambiada con éxito." @@ -7981,7 +7956,7 @@ msgstr "Eliminar conexión al servidor" msgid "Server deleted." msgstr "Servidor eliminado." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7995,7 +7970,7 @@ msgstr "" "apariencia mediante temas. Tanto el interfaz de administración como las " "páginas web producidas son adecuados para dispositivos móviles." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8009,7 +7984,7 @@ msgstr "" "en el interfaz de administrador para tener mejores URLs de acceso a tus " "páginas y artículos." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8020,7 +7995,7 @@ msgstr "" "href=\"/wordpress/wp-admin/\">página de administración para acceder a " "ella en el futuro." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8030,12 +8005,12 @@ msgstr "" "de administración una actualización de la base de datos. Se pueden instalar " "y actualizar plugins y temas adicionales asumiendo los riesgos." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Sitio web y Blog" @@ -8052,7 +8027,7 @@ msgstr "" "WordPress o blog a los administradores. Habilítalo solo después de ejecutar " "la configuración inicial de WordPress." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8074,7 +8049,7 @@ msgstr "" "de mapa y calendario. Se pueden compartir fotos sueltas con otras personas " "enviándoles un enlace directo." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8085,11 +8060,11 @@ msgstr "" "Para añadir más usuarios hay que crear cuentas con el mismo nombre tanto en " "Zoph como en {box_name} ." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Organizador de fotografías" @@ -8141,102 +8116,96 @@ msgstr "Esperando a empezar: {name}" msgid "Finished: {name}" msgstr "Terminó: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "El paquete {expression} no está disponible para instalar" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "El paquete {package_name} es la última versión ({latest_version})" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "Error al respaldar" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "instalando" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "descargando" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "cambio de medio" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "archivo de configuración: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Tiempo máximo esperando al administrador de paquetes" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Instalando app" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Actualizando app" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Error al instalar la app: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Error al actualizar la aplicación: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Error al instalar la app: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Error al actualizar la app: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "App instalada." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "App actualizada" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Instalando app" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing app: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Error al instalar la app: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing app: {error}" msgid "Error uninstalling app: {error}" msgstr "Error al instalar la app: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "App installed." msgid "App uninstalled." msgstr "App instalada." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Actualizando los paquetes de la app" @@ -8296,53 +8265,54 @@ msgstr "Instalación" msgid "Service %(service_name)s is not running." msgstr "El servidor %(service_name)s no se está ejecutando." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Funcionalidad central e interfaz web para %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Inicio" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Principal" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Aplicaciones" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Aplicaciones" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Sistema" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Sistema" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Cambiar clave de acceso" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Apagar" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Cerrar sesión" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Seleccionar idioma" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Iniciar sesión" @@ -8631,6 +8601,77 @@ msgstr "" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Activar DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Activar Extensiones de Seguridad del Sistema de Nombre de Dominios" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "El servicio firewall no se está ejecutando. Por favor actívelo. El " +#~ "firewall viene activado por defecto en su %(box_name)s. En cualquier " +#~ "sistema basado en Debian (como %(box_name)s) puede activarlo con 'service " +#~ "firewalld start' o si su sistema emplea systemd 'systemctl start " +#~ "firewalld'." + +#~ msgid "Migrate to ECC" +#~ msgstr "Migrar a crioptografía ECC (basada en curvas elípticas)" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Actualmemte tu instalación OpenVPN está usando RSA. Cambiar a " +#~ "Criptografía de Curva Elíptica (ECC) mejora la velocidad y seguridad al " +#~ "establecer conexiones. Esta operación es irreversible. En la mayoría de " +#~ "computadores monoplaca debería tardar escasos minutos." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Todas las instalaciones nuevas de OpenVPN sobre %(box_name)s usarán ECC " +#~ "de serie. Recomendamos migrar cuanto antes." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Aviso: Esta operación invalidará los perfiles de cliente " +#~ "existentes. Todos los usuarios de OpenVPN en %(box_name)s tienen que " +#~ "descargar sus perfiles nuevos. Para conectar con este servidor tendrán " +#~ "que usar clientes OpenVPN compatibles con ECC." + +#~ msgid "Migrate" +#~ msgstr "Migrar" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "Acceso SSH con clave desactivado." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Acceso SSH con clave activado." + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "Error al respaldar" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Funcionalidad central e interfaz web para %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Conexiones de red" diff --git a/plinth/locale/fa/LC_MESSAGES/django.po b/plinth/locale/fa/LC_MESSAGES/django.po index 89ac45c0a..554f9ef7e 100644 --- a/plinth/locale/fa/LC_MESSAGES/django.po +++ b/plinth/locale/fa/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Persian calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Create Connection" msgid "Name of the new library" msgstr "ساختن اتصال" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1126,22 +1117,22 @@ msgstr "" msgid "Delete library %(library)s" msgstr "سایت %(site)s را پاک کنید" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 #, fuzzy #| msgid "Error occurred while publishing key." msgid "An error occurred while creating the library." msgstr "هنگام انتشار کلید خطایی رخ داد." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} پاک شد." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "نشد که {name} پاک شود: {error}" @@ -1181,25 +1172,25 @@ msgstr "" msgid "Server Administration" msgstr "حساب مدیر" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "پیکربندی عمومی" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 #, fuzzy msgid "Configure" msgstr "پیکربندی" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1307,49 +1298,49 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "خطا در هنگام تنظیم نام میزبان: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "نام میزبان تنظیم شد" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "خطا در هنگام تنظیم نام دامنه: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "نام دامنه تنظیم شد" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, fuzzy, python-brace-format #| msgid "Error setting hostname: {exception}" msgid "Error setting webserver home page: {exception}" msgstr "خطا در هنگام تنظیم نام میزبان: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, fuzzy, python-brace-format #| msgid "Error setting domain name: {exception}" msgid "Error changing advanced mode: {exception}" msgstr "خطا در هنگام تنظیم نام دامنه: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1357,7 +1348,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as یا سرویس رایگان به‌روزرسانی نشانی را در freedns.afraid.org به کار ببرید." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 #, fuzzy msgid "Dynamic DNS Client" msgstr "برنامهٔ DNS متغیر (Dynamic DNS Client)" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 #, fuzzy #| msgid "Domain Name" msgid "Dynamic Domain Name" @@ -1779,7 +1770,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1847,13 +1838,13 @@ msgstr "پاک‌کردن اتصال" msgid "Already up-to-date" msgstr "آخرین به‌روزرسانی" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 #, fuzzy #| msgid "Web Server" msgid "Chat Server" @@ -1985,14 +1976,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2000,7 +1991,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2010,13 +2001,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2159,7 +2150,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2170,7 +2161,7 @@ msgstr "" "خروجی شبکه را در {box_name} شما کنترل می‌کند. فعال نگه‌داشتن فایروال و تنظیم " "درست آن خطر تهدیدهای امنیتی از طرف اینترنت را کم می‌کند." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "فایروال" @@ -2190,52 +2181,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"برنامهٔ فایروال در حال اجرا نیست. لطفاً آن را اجرا کنید. فایروال به طور پیش‌فرض " -"در %(box_name)s روشن است. روش روشن‌کردن آن در سیستم‌های برپایهٔ Debian (مانند " -"%(box_name)s) با فرمان 'service firewalld start' و در سیستم‌های دارای systemd " -"با فرمان 'systemctl start firewalld' است." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "سرویس/پورت" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "فعال" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "غیرفعال" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "مجاز" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "مجاز (فقط داخلی)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "مجاز (فقط خارجی)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "مسدود" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2244,13 +2222,13 @@ msgstr "" "کارکرد فایروال خودکار است. وقتی که یک سرویس را فعال کنید آن سرویس در فایروال " "هم مجاز می‌شود و وقتی آن را غیرفعال کنید در فایروال هم مسدود می‌شود." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2297,7 +2275,7 @@ msgstr "آغاز راه‌اندازی" msgid "Setup Complete" msgstr "راه‌اندازی کامل شد" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2308,83 +2286,83 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository URL." msgstr "نام میزبان معتبر نیست" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository name." msgstr "نام میزبان معتبر نیست" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Create Connection" msgid "Private repository" msgstr "ساختن اتصال" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Create Connection" msgid "Name of the repository" msgstr "ساختن اتصال" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Default" msgid "Default branch" msgstr "پیش‌فرض" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2439,21 +2417,21 @@ msgstr "پاک‌کردن ویکی یا وبلاگ %(name)s" msgid "Delete this repository permanently?" msgstr "اتصال %(name)s را برای همیشه پاک می‌کنید؟" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 #, fuzzy #| msgid "Error occurred while publishing key." msgid "An error occurred while creating the repository." msgstr "هنگام انتشار کلید خطایی رخ داد." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 #, fuzzy #| msgid "Create Connection" msgid "Edit repository" @@ -2788,7 +2766,7 @@ msgstr "دربارهٔ {box_name}" msgid "{box_name} Manual" msgstr "کتاب راهنمای {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2796,7 +2774,7 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 #, fuzzy #| msgid "" #| "For more information about the %(box_name)s project, see the ویکی %(box_name)s را ببینید." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 #, fuzzy msgid "Manage I2P application" msgstr "فعال‌سازی برنامه" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 #, fuzzy msgid "Anonymity Network" msgstr "رفتن به تنظیمات شبکه" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2865,7 +2843,7 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 #, fuzzy #| msgid "" #| "ikiwiki is a simple wiki and blog application. It supports several " @@ -2882,7 +2860,7 @@ msgstr "" "پشتیبانی می‌کند. اگر این برنامه فعال باشد، وبلاگ‌ها و ویکی‌ها از نشانی /ikiwiki قابل دسترس خواهند بود." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2891,17 +2869,17 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 #, fuzzy #| msgid "Manage Wikis and Blogs" msgid "Wiki and Blog" msgstr "مدیریت ویکی‌ها و وبلاگ‌ها" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 #, fuzzy msgid "View and edit wiki applications" msgstr "سرویس‌ها و برنامه‌ها" @@ -2958,43 +2936,43 @@ msgstr "" "این کار همهٔ نوشته‌ها، صفحه‌ها، نظرها، و تاریخچهٔ آن‌ها را حذف می‌کند. آیا به " "پاک‌کردن ویکی یا وبلاگ ادامه می‌دهید؟" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "ویکی {name} ساخته شد." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "ساختن ویکی شکست خورد: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "وبلاگ {name} ساخته شد." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "ساختن وبلاگ شکست خورد: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, fuzzy, python-brace-format #| msgid "{name} deleted." msgid "{title} deleted." msgstr "{name} پاک شد." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, fuzzy, python-brace-format #| msgid "Could not delete {name}: {error}" msgid "Could not delete {title}: {error}" msgstr "نشد که {name} پاک شود: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3002,11 +2980,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 #, fuzzy #| msgid "Web Server" msgid "Gobby Server" @@ -3054,7 +3032,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -3072,7 +3050,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "A digital certficate allows users of a web service to verify the identity " @@ -3093,7 +3071,7 @@ msgstr "" "برای این کار {box_name} به Let's Encrypt (که یک مرجع صدور گواهی دیجیتال است) " "اثبات می‌کند که مالک دامنه است." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 #, fuzzy #| msgid "" #| "Let's Encrypt is a free, automated, and open certificate authority, run " @@ -3113,19 +3091,19 @@ msgstr "" "\"https://letsencrypt.org/repository/\">قرارداد اشتراک Let's Encrypt " "بخوانید و آن را بپذیرید." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 #, fuzzy #| msgid "Certificates (Let's Encrypt)" msgid "Let's Encrypt" msgstr "گواهی دیجیتال (Let's Encrypt)" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 #, fuzzy #| msgid "Certificate Status" msgid "Certificates" msgstr "وضعیت گواهی دیجیتال" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3194,7 +3172,7 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, fuzzy, python-brace-format #| msgid "Certificate successfully revoked for domain {domain}" msgid "" @@ -3202,36 +3180,36 @@ msgid "" "moments to take effect." msgstr "گواهی دامنهٔ {domain} با موفقیت باطل شد" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "باطل‌کردن گواهی دامنهٔ {domain} شکست خورد: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "گواهی دیجیتال برای دامنهٔ {domain} با موفقیت گرفته شد" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "گرفتن گواهی برای دامنهٔ {domain} شکست خورد: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, fuzzy, python-brace-format #| msgid "Certificate successfully revoked for domain {domain}" msgid "Certificate successfully deleted for domain {domain}" msgstr "گواهی دامنهٔ {domain} با موفقیت باطل شد" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, fuzzy, python-brace-format #| msgid "Failed to revoke certificate for domain {domain}: {error}" msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "باطل‌کردن گواهی دامنهٔ {domain} شکست خورد: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3241,14 +3219,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -3330,7 +3308,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3338,7 +3316,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3347,18 +3325,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3437,42 +3415,42 @@ msgstr "رمز" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 #, fuzzy msgid "Public registrations enabled" msgstr "برنامه نصب شد." -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 #, fuzzy msgid "Public registrations disabled" msgstr "برنامه نصب شد." -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 #, fuzzy msgid "Private mode disabled" msgstr "برنامه نصب شد." -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "نام دامنه تنظیم شد" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "نام دامنه تنظیم شد" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, fuzzy, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3485,11 +3463,11 @@ msgstr "" "برای اتصال به سرور به یک برنامهٔ ماین‌تست نیاز است." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 #, fuzzy msgid "Block Sandbox" msgstr "بازی مکعب‌ها (Minetest)" @@ -3540,7 +3518,7 @@ msgstr "" msgid "Address" msgstr "نشانی" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3715,19 +3693,19 @@ msgstr "پوستهٔ ایمن" msgid "Services" msgstr "سرویس" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "شبکه‌ها" @@ -4105,7 +4083,7 @@ msgstr "ویرایش اتصال" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "ویرایش" @@ -4210,7 +4188,7 @@ msgstr "آی‌پی ن۴" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "روش" @@ -4226,7 +4204,7 @@ msgstr "دی‌ان‌اس" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "پیش‌فرض" @@ -4239,7 +4217,7 @@ msgid "This connection is not active." msgstr "این اتصال فعال نیست." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "امنیت" @@ -4837,7 +4815,7 @@ msgstr "اتصال {name} پاک شد." msgid "Failed to delete connection: Connection not found." msgstr "پاک‌کردن اتصال شکست خورد: اتصال پیدا نشد." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4848,24 +4826,24 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection Type" msgid "Connect to VPN services" msgstr "نوع اتصال" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 #, fuzzy #| msgid "Open" msgid "OpenVPN" msgstr "باز" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4875,63 +4853,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -#, fuzzy -#| msgid "Mode" -msgid "Migrate" -msgstr "حالت" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4940,33 +4884,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4975,89 +4919,89 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 #, fuzzy #| msgid "Available Domains" msgid "PageKite Domain" msgstr "دامنه‌های موجود" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -5091,29 +5035,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5155,8 +5099,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -5198,6 +5142,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5229,7 +5204,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5240,7 +5215,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -5260,7 +5235,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5270,19 +5245,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5343,7 +5318,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 #, fuzzy #| msgid "Configuration updated" msgid "Access rights configuration updated" @@ -5413,7 +5388,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5426,13 +5401,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5441,31 +5416,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 #, fuzzy #| msgid "Interface" msgid "Network File Storage" @@ -5553,18 +5528,18 @@ msgstr "مشترک" msgid "Action" msgstr "کنش‌ها" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy msgid "FreedomBox OS disk" msgstr "FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 #, fuzzy #| msgid "Shared" msgid "Open Share" msgstr "مشترک" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 #, fuzzy #| msgid "Shared" msgid "Group Share" @@ -5600,55 +5575,55 @@ msgstr "مشترک" msgid "Error disabling share: {error_message}" msgstr "خطا هنگام نصب برنامه: {error}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 #, fuzzy #| msgid "Web Server" msgid "Web Search" msgstr "سرور وب" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 #, fuzzy #| msgid "Mode" msgid "Moderate" msgstr "حالت" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5814,14 +5789,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5830,103 +5805,103 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 #, fuzzy #| msgid "Service" msgid "Server" msgstr "سرویس" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 #, fuzzy #| msgid "Shared" msgid "Sharing" msgstr "مشترک" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 #, fuzzy #| msgid "Publish Key" msgid "Public share" msgstr "انتشار کلید" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5969,32 +5944,32 @@ msgstr "مشترک" msgid "Add Share" msgstr "مشترک" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 #, fuzzy #| msgid "Shared" msgid "Share edited." msgstr "مشترک" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 #, fuzzy #| msgid "Shared" msgid "Edit Share" msgstr "مشترک" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 #, fuzzy #| msgid "{name} deleted." msgid "Share deleted." msgstr "{name} پاک شد." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6002,14 +5977,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 #, fuzzy #| msgid "Delete %(name)s" msgid "Storage Snapshots" @@ -6115,7 +6090,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 #, fuzzy #| msgid "Delete %(name)s" msgid "Delete Snapshots" @@ -6165,65 +6140,65 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Last update" msgid "manually created" msgstr "آخرین به‌روزرسانی" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 #, fuzzy #| msgid "Delete %(name)s" msgid "Manage Snapshots" msgstr "پاک‌کردن %(name)s" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 #, fuzzy #| msgid "Configuration updated" msgid "Storage snapshots configuration updated" msgstr "پیکربندی به‌روز شد" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 #, fuzzy #| msgid "Delete %(name)s" msgid "Deleted selected snapshots" msgstr "پاک‌کردن %(name)s" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6231,7 +6206,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -6270,14 +6245,6 @@ msgstr "" msgid "Fingerprint" msgstr "اثر انگشت SSH" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -6292,7 +6259,7 @@ msgstr "" msgid "Logged out successfully." msgstr "پارتیشن با موفقیت بزرگ شد." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6300,153 +6267,153 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, fuzzy, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size} بایت" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, fuzzy, python-brace-format #| msgid "{disk_size} KiB" msgid "{disk_size:.1f} KiB" msgstr "{disk_size} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, fuzzy, python-brace-format #| msgid "{disk_size} MiB" msgid "{disk_size:.1f} MiB" msgstr "{disk_size} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, fuzzy, python-brace-format #| msgid "{disk_size} GiB" msgid "{disk_size:.1f} GiB" msgstr "{disk_size} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, fuzzy, python-brace-format #| msgid "{disk_size} TiB" msgid "{disk_size:.1f} TiB" msgstr "{disk_size} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 #, fuzzy #| msgid "The requested domain is already registered." msgid "The device is already mounted." msgstr "دامنهٔ درخواستی از قبل ثبت شده است." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid directory name." msgstr "نام میزبان معتبر نیست" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 #, fuzzy #| msgid "Shared" msgid "Share" msgstr "مشترک" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6486,7 +6453,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "بزرگ‌کردن پارتیشن ریشه" @@ -6507,30 +6474,30 @@ msgstr "" "%(expandable_root_size)s فضای خالی در اختیار پارتیشن ریشهٔ شما قرار خواهد " "گرفت." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "خطا در هنگام بزرگ‌کردن پارتیشن: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "پارتیشن با موفقیت بزرگ شد." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6538,7 +6505,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6550,20 +6517,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6572,47 +6539,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6712,13 +6679,13 @@ msgstr "سرویس" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "Current Network Configuration" msgid "Updating configuration" msgstr "پیکربندی فعلی شبکه" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6771,31 +6738,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6803,12 +6770,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6816,8 +6783,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -6825,28 +6792,28 @@ msgstr "" msgid "Software Update" msgstr "{name} پاک شد." -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy msgid "FreedomBox Updated" msgstr "FreedomBox" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy msgid "Distribution update started" msgstr "برنامه نصب شد." -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7005,53 +6972,53 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "برنامه نصب شد." -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy msgid "Distribution upgrade disabled" msgstr "برنامه نصب شد." -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy msgid "Starting distribution upgrade test." msgstr "برنامه نصب شد." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7059,15 +7026,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -7087,25 +7054,25 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 #, fuzzy #| msgid "Administrator Account" msgid "Authorization Password" msgstr "حساب مدیر" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Show password" msgid "Invalid password." msgstr "رمز را نشان بده" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7114,13 +7081,13 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "ساختن کاربر LDAP شکست خورد." -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to {group} group: {error}" @@ -7137,45 +7104,45 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 #, fuzzy #| msgid "Failed to add new user to admin group." msgid "Failed to change user status." msgstr "افزودن کاربر به گروه مدیران شکست خورد." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "افزودن کاربر به گروه مدیران شکست خورد." -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, fuzzy, python-brace-format #| msgid "Failed to obtain certificate for domain {domain}: {error}" msgid "Failed to restrict console access: {error}" msgstr "گرفتن گواهی برای دامنهٔ {domain} شکست خورد: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "حساب کاربری ساخته شد، شما الان وارد سیستم هستید" @@ -7192,12 +7159,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -7242,17 +7209,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -7284,34 +7251,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7660,7 +7627,7 @@ msgstr "پاک‌کردن اتصال" msgid "Server deleted." msgstr "{name} پاک شد." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7669,7 +7636,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7678,28 +7645,28 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 #, fuzzy #| msgid "Address" msgid "WordPress" msgstr "نشانی" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Manage Wikis and Blogs" msgid "Website and Blog" @@ -7717,7 +7684,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7730,7 +7697,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7738,11 +7705,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7794,107 +7761,101 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "خظا هنگام پشتیبان‌گیری" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format msgid "Error installing app: {string} {details}" msgstr "خطا هنگام نصب برنامه: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format msgid "Error updating app: {string} {details}" msgstr "خطا هنگام نصب برنامه: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "خطا هنگام نصب برنامه: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "خطا هنگام نصب برنامه: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy msgid "App installed." msgstr "برنامه نصب شد." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "آخرین به‌روزرسانی" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "خطا هنگام نصب برنامه: {error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "خطا هنگام نصب برنامه: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "خطا هنگام نصب برنامه: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy msgid "App uninstalled." msgstr "برنامه نصب شد." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7945,57 +7906,58 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 #, fuzzy msgid " Apps" msgstr "برنامه‌ها" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 #, fuzzy msgid "Apps" msgstr "برنامه‌ها" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 #, fuzzy #| msgid "Language" msgid "Select language" msgstr "زبان" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -8265,6 +8227,33 @@ msgstr "" msgid "Gujarati" msgstr "" +#, fuzzy +#~| msgid "Enable Dynamic DNS" +#~ msgid "Enable DNSSEC" +#~ msgstr "فعال‌سازی DNS متغیر" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "برنامهٔ فایروال در حال اجرا نیست. لطفاً آن را اجرا کنید. فایروال به طور " +#~ "پیش‌فرض در %(box_name)s روشن است. روش روشن‌کردن آن در سیستم‌های برپایهٔ " +#~ "Debian (مانند %(box_name)s) با فرمان 'service firewalld start' و در " +#~ "سیستم‌های دارای systemd با فرمان 'systemctl start firewalld' است." + +#, fuzzy +#~| msgid "Mode" +#~ msgid "Migrate" +#~ msgstr "حالت" + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "خظا هنگام پشتیبان‌گیری" + #~ msgid "Network Connections" #~ msgstr "اتصال‌های شبکه" diff --git a/plinth/locale/fake/LC_MESSAGES/django.po b/plinth/locale/fake/LC_MESSAGES/django.po index dfff9cc3a..faa5e7dcb 100644 --- a/plinth/locale/fake/LC_MESSAGES/django.po +++ b/plinth/locale/fake/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Plinth 0.6\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2016-01-31 22:24+0530\n" "Last-Translator: Sunil Mohan Adapa \n" "Language-Team: Plinth Developers calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Create User" msgid "Name of the new library" msgstr "CREATE USER" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 #, fuzzy #| msgid "This service already exists" msgid "A library with this name already exists." @@ -1170,24 +1161,24 @@ msgstr "" msgid "Delete library %(library)s" msgstr "DELETE SITE %(site)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 #, fuzzy #| msgid "packages not found" msgid "Library created." msgstr "PACKAGES NOT FOUND" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 #, fuzzy #| msgid "An error occurred during configuration." msgid "An error occurred while creating the library." msgstr "AN ERROR OCCURRED DURING CONFIGURATION." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} DELETED." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "COULD NOT DELETE {name}: {error}" @@ -1232,24 +1223,24 @@ msgstr "" msgid "Server Administration" msgstr "SERVER DOMAIN" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "GENERAL CONFIGURATION" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "CONFIGURE" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1361,49 +1352,49 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "ERROR SETTING HOSTNAME: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "HOSTNAME SET" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "ERROR SETTING DOMAIN NAME: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "DOMAIN NAME SET" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, fuzzy, python-brace-format #| msgid "Error setting hostname: {exception}" msgid "Error setting webserver home page: {exception}" msgstr "ERROR SETTING HOSTNAME: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, fuzzy, python-brace-format #| msgid "Error setting domain name: {exception}" msgid "Error changing advanced mode: {exception}" msgstr "ERROR SETTING DOMAIN NAME: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1411,7 +1402,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as /DELUGE PATH ON THE WEB SERVER. THE DEFAULT PASSWORD IS 'DELUGE', BUT " "YOU SHOULD LOG IN AND CHANGE IT IMMEDIATELY AFTER ENABLING THIS SERVICE." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 #, fuzzy #| msgid "Enable Deluge" msgid "Deluge" msgstr "ENABLE DELUGE" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 #, fuzzy #| msgid "BitTorrent Web Client (Deluge)" @@ -1647,7 +1638,7 @@ msgstr "RESULT" msgid "Diagnostic Test" msgstr "DIAGNOSTIC TEST" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, fuzzy, python-brace-format #| msgid "" #| "If your internet provider changes your IP address periodic (i.e. every " @@ -1663,7 +1654,7 @@ msgstr "" "IT MAY BE HARD FOR OTHERS TO FIND YOU IN THE WEB. AND FOR THIS REASON NOBODY " "MAY FIND THE SERVICES WHICH ARE PROVIDED BY %(box_name)s, SUCH AS OWNCLOUD." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 #, fuzzy #| msgid "" #| "The solution is to assign a DNS name to your IP address and update the " @@ -1689,7 +1680,7 @@ msgstr "" "THE SERVER WILL ASSIGN YOUR DNS NAME WITH THE NEW IP AND IF SOMEONE FROM THE " "INTERNET ASKS FOR YOUR DNS NAME HE WILL GET YOUR CURRENT IP ANSWERED." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 #, fuzzy #| msgid "" #| "If you are looking for a free dynamic DNS account, you may find a free " @@ -1709,11 +1700,11 @@ msgstr "" "BASED SERVICES ON " "FREEDNS.AFRAID.ORG." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "DYNAMIC DNS CLIENT" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 #, fuzzy #| msgid "Domain Name" msgid "Dynamic Domain Name" @@ -1863,7 +1854,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1932,7 +1923,7 @@ msgstr "DELETE CONNECTION" msgid "Already up-to-date" msgstr "LAST UPDATE" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1940,7 +1931,7 @@ msgstr "" "XMPP IS AN OPEN AND STANDARDIZED COMMUNICATION PROTOCOL. HERE YOU CAN RUN " "AND CONFIGURE YOUR XMPP SERVER, CALLED EJABBERD." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, fuzzy, python-brace-format #| msgid "" #| "To actually communicate, you can use the web client " @@ -1956,19 +1947,19 @@ msgstr "" "ANY OTHER XMPP CLIENT." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 #, fuzzy #| msgid "Web Server" msgid "Chat Server" @@ -2082,14 +2073,14 @@ msgstr "" "LIKE USERNAME@%(domainname)s. YOU CAN SETUP YOUR DOMAIN ON THE SYSTEM " "CONFIGURE PAGE." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2097,7 +2088,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2107,13 +2098,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2258,7 +2249,7 @@ msgstr "PORT" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, fuzzy, python-brace-format #| msgid "" #| "Firewall is a security system that controls the incoming and outgoing " @@ -2273,7 +2264,7 @@ msgstr "" "NETWORK TRAFFIC ON YOUR %(box_name)s. KEEPING A FIREWALL ENABLED AND " "PROPERLY CONFIGURED REDUCES RISK OF SECURITY THREAT FROM THE INTERNET." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "FIREWALL" @@ -2295,52 +2286,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"FIREWALL DAEMON IS NOT RUNNING. PLEASE RUN IT. FIREWALL COMES ENABLED BY " -"DEFAULT ON %(box_name)s. ON ANY DEBIAN BASED SYSTEM (SUCH AS %(box_name)s) " -"YOU MAY RUN IT USING THE COMMAND 'SERVICE FIREWALLD START' OR IN CASE OF A " -"SYSTEM WITH SYSTEMD 'SYSTEMCTL START FIREWALLD'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "SERVICE/PORT" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "ENABLED" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "DISABLED" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "PERMITTED" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "PERMITTED (INTERNAL ONLY)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "PERMITTED (EXTERNAL ONLY)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "BLOCKED" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2350,13 +2328,13 @@ msgstr "" "ALSO PERMITTED IN THE FIREWALL AND WHEN YOU DISABLE A SERVICE IT IS ALSO " "DISABLED IN THE FIREWALL." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2404,7 +2382,7 @@ msgstr "START SETUP" msgid "Setup Complete" msgstr "SETUP COMPLETE" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2415,87 +2393,87 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository URL." msgstr "INVALID HOSTNAME" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository name." msgstr "INVALID HOSTNAME" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 #, fuzzy #| msgid "packages not found" msgid "Repository's owner name" msgstr "PACKAGES NOT FOUND" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Create User" msgid "Private repository" msgstr "CREATE USER" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 #, fuzzy #| msgid "This service already exists" msgid "A repository with this name already exists." msgstr "THIS SERVICE ALREADY EXISTS" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Create User" msgid "Name of the repository" msgstr "CREATE USER" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Default" msgid "Default branch" msgstr "DEFAULT" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2550,25 +2528,25 @@ msgstr "DELETE WIKI OR BLOG %(name)s" msgid "Delete this repository permanently?" msgstr "DELETE USER PERMANENTLY?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 #, fuzzy #| msgid "packages not found" msgid "Repository created." msgstr "PACKAGES NOT FOUND" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 #, fuzzy #| msgid "An error occurred during configuration." msgid "An error occurred while creating the repository." msgstr "AN ERROR OCCURRED DURING CONFIGURATION." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 #, fuzzy #| msgid "packages not found" msgid "Repository edited." msgstr "PACKAGES NOT FOUND" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 #, fuzzy #| msgid "Create User" msgid "Edit repository" @@ -2914,7 +2892,7 @@ msgstr "ABOUT {box_name}" msgid "{box_name} Manual" msgstr "{box_name} MANUAL" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2922,7 +2900,7 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 #, fuzzy #| msgid "" #| "For more information about the %(box_name)s project, see the %(box_name)s WIKI." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 #, fuzzy #| msgid "Applications" msgid "Manage I2P application" msgstr "APPLICATIONS" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 #, fuzzy #| msgid "Tor Anonymity Network" msgid "Anonymity Network" msgstr "TOR ANONYMITY NETWORK" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 #, fuzzy #| msgid "Privoxy Web Proxy" msgid "I2P Proxy" @@ -2995,14 +2973,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -3011,17 +2989,17 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 #, fuzzy #| msgid "wiki" msgid "ikiwiki" msgstr "WIKI" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "WIKI AND BLOG" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 #, fuzzy #| msgid "Services and Applications" msgid "View and edit wiki applications" @@ -3079,43 +3057,43 @@ msgstr "" "THIS ACTION WILL REMOVE ALL THE POSTS, PAGES AND COMMENTS INCLUDING REVISION " "HISTORY. DELETE THIS WIKI OR BLOG PERMANENTLY?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "CREATED WIKI {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "COULD NOT CREATE WIKI: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "CREATED BLOG {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "COULD NOT CREATE BLOG: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, fuzzy, python-brace-format #| msgid "{name} deleted." msgid "{title} deleted." msgstr "{name} DELETED." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, fuzzy, python-brace-format #| msgid "Could not delete {name}: {error}" msgid "Could not delete {title}: {error}" msgstr "COULD NOT DELETE {name}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3123,11 +3101,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 #, fuzzy #| msgid "Web Server" msgid "Gobby Server" @@ -3175,7 +3153,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -3195,7 +3173,7 @@ msgstr "" msgid "Chat Client" msgstr "IRC CLIENT (QUASSEL)" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "A digital certficate allows users of a web service to verify the identity " @@ -3216,7 +3194,7 @@ msgstr "" "DOMAIN. IT DOES SO BY PROVING ITSELF TO BE THE OWNER OF A DOMAIN TO LET'S " "ENCRYPT, A CERTFICATE AUTHORITY (CA)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 #, fuzzy #| msgid "" #| "Let's Encrypt is a free, automated, and open certificate authority, run " @@ -3235,19 +3213,19 @@ msgstr "" "READ AND AGREE WITH THE LET'S ENCRYPT SUBSCRIBER AGREEMENT BEFORE USING THIS SERVICE." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 #, fuzzy #| msgid "Certificates (Let's Encrypt)" msgid "Let's Encrypt" msgstr "CERTIFICATES (LET'S ENCRYPT)" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 #, fuzzy #| msgid "Certificate Status" msgid "Certificates" msgstr "CERTIFICATE STATUS" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3318,7 +3296,7 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, fuzzy, python-brace-format #| msgid "Certificate successfully revoked for domain {domain}" msgid "" @@ -3326,36 +3304,36 @@ msgid "" "moments to take effect." msgstr "CERTIFICATE SUCCESSFULLY REVOKED FOR DOMAIN {domain}" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "FAILED TO REVOKE CERTIFICATE FOR DOMAIN {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "CERTIFICATE SUCCESSFULLY OBTAINED FOR DOMAIN {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "FAILED TO OBTAIN CERTIFICATE FOR DOMAIN {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, fuzzy, python-brace-format #| msgid "Certificate successfully revoked for domain {domain}" msgid "Certificate successfully deleted for domain {domain}" msgstr "CERTIFICATE SUCCESSFULLY REVOKED FOR DOMAIN {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, fuzzy, python-brace-format #| msgid "Failed to revoke certificate for domain {domain}: {error}" msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "FAILED TO REVOKE CERTIFICATE FOR DOMAIN {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3365,14 +3343,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 #, fuzzy #| msgid "Chat Server (XMPP)" msgid "Matrix Synapse" @@ -3464,7 +3442,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3472,7 +3450,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3481,18 +3459,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3573,49 +3551,49 @@ msgstr "PASSWORD" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 #, fuzzy #| msgid "Applications" msgid "Public registrations enabled" msgstr "APPLICATIONS" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 #, fuzzy #| msgid "Applications" msgid "Public registrations disabled" msgstr "APPLICATIONS" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 #, fuzzy #| msgid "PageKite enabled" msgid "Private mode enabled" msgstr "PAGEKITE ENABLED" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 #, fuzzy #| msgid "PageKite disabled" msgid "Private mode disabled" msgstr "PAGEKITE DISABLED" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 #, fuzzy #| msgid "Setting unchanged" msgid "Default skin changed" msgstr "SETTING UNCHANGED" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "DOMAIN NAME SET" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "DOMAIN NAME SET" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3624,11 +3602,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 #, fuzzy #| msgid "Blocked" msgid "Block Sandbox" @@ -3681,7 +3659,7 @@ msgstr "" msgid "Address" msgstr "ADDRESS" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3866,19 +3844,19 @@ msgstr "SECURE SHELL (SSH)" msgid "Services" msgstr "SERVICE" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "NETWORKS" @@ -4259,7 +4237,7 @@ msgstr "EDIT CONNECTION" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "EDIT" @@ -4364,7 +4342,7 @@ msgstr "IPV4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "METHOD" @@ -4380,7 +4358,7 @@ msgstr "DNS SERVER" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "DEFAULT" @@ -4393,7 +4371,7 @@ msgid "This connection is not active." msgstr "THIS CONNECTION IS NOT ACTIVE." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "SECURITY" @@ -4991,7 +4969,7 @@ msgstr "CONNECTION {name} DELETED." msgid "Failed to delete connection: Connection not found." msgstr "FAILED TO DELETE CONNECTION: CONNECTION NOT FOUND." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, fuzzy, python-brace-format #| msgid "" #| "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -5015,26 +4993,26 @@ msgstr "" "YOU CAN ALSO ACCESS THE REST OF THE INTERNET VIA %(box_name)s FOR ADDED " "SECURITY AND ANONYMITY." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection Type" msgid "Connect to VPN services" msgstr "CONNECTION TYPE" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 #, fuzzy #| msgid "OpenVPN" msgid "OpenVPN" msgstr "OPENVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 #, fuzzy #| msgid "Virtual Private Network (OpenVPN)" msgid "Virtual Private Network" msgstr "VIRTUAL PRIVATE NETWORK (OPENVPN)" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5044,45 +5022,11 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -#, fuzzy -#| msgid "Mode" -msgid "Migrate" -msgstr "MODE" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "PROFILE" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, fuzzy, python-format #| msgid "" #| "To connect to %(box_name)s's VPN, you need to download a profile and feed " @@ -5093,8 +5037,8 @@ msgstr "PROFILE" #| "how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "TO CONNECT TO %(box_name)s's VPN, YOU NEED TO DOWNLOAD A PROFILE AND FEED IT " @@ -5104,16 +5048,17 @@ msgstr "" "\">DOCUMENTATION ON RECOMMENDED CLIENTS AND INSTRUCTIONS ON HOW TO " "CONFIGURE THEM." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "PROFILE IS SPECIFIC TO EACH USER OF %(box_name)s. KEEP IT A SECRET." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "DOWNLOAD MY PROFILE" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, fuzzy, python-brace-format #| msgid "" #| "PageKite is a system for exposing %(box_name)s services when you don't " @@ -5131,13 +5076,13 @@ msgstr "" "SERVICES ARE UNREACHABLE FROM THE REST OF THE INTERNET. THIS INCLUDES THE " "FOLLOWING SITUATIONS:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, fuzzy, python-brace-format #| msgid "%(box_name)s is behind a restricted firewall." msgid "{box_name} is behind a restricted firewall." msgstr "%(box_name)s IS BEHIND A RESTRICTED FIREWALL." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, fuzzy, python-brace-format #| msgid "" #| "%(box_name)s is connected to a (wireless) router which you don't control." @@ -5145,7 +5090,7 @@ msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "%(box_name)s IS CONNECTED TO A (WIRELESS) ROUTER WHICH YOU DON'T CONTROL." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5153,7 +5098,7 @@ msgstr "" "YOUR ISP DOES NOT PROVIDE YOU AN EXTERNAL IP ADDRESS AND INSTEAD PROVIDES " "INTERNET CONNECTION THROUGH NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 #, fuzzy #| msgid "" #| "Your ISP does not provide you a static IP address and your IP address " @@ -5165,11 +5110,11 @@ msgstr "" "YOUR ISP DOES NOT PROVIDE YOU A STATIC IP ADDRESS AND YOUR IP ADDRESS " "CHANGES EVERTIME YOU CONNECT TO INTERNET." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "YOUR ISP LIMITS INCOMING CONNECTIONS." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, fuzzy, python-brace-format #| msgid "" #| "PageKite works around NAT, firewalls and IP-address limitations by using " @@ -5188,29 +5133,29 @@ msgstr "" "PROVIDER, FOR EXAMPLE PAGEKITE.NET. IN " "FUTURE IT MIGHT BE POSSIBLE TO USE YOUR BUDDY'S %(box_name)s FOR THIS." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 #, fuzzy #| msgid "Pagekite" msgid "PageKite" msgstr "PAGEKITE" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 #, fuzzy #| msgid "Public Visibility (PageKite)" msgid "Public Visibility" msgstr "PUBLIC VISIBILITY (PAGEKITE)" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 #, fuzzy #| msgid "PageKite Account" msgid "PageKite Domain" msgstr "PAGEKITE ACCOUNT" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "SERVER DOMAIN" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5218,31 +5163,31 @@ msgstr "" "SELECT YOUR PAGEKITE SERVER. SET \"PAGEKITE.NET\" TO USE THE DEFAULT " "PAGEKITE.NET SERVER." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "SERVER PORT" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "PORT OF YOUR PAGEKITE SERVER (DEFAULT: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "KITE NAME" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "EXAMPLE: MYBOX.PAGEKITE.ME" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "INVALID KITE NAME" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "KITE SECRET" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5250,27 +5195,27 @@ msgstr "" "A SECRET ASSOCIATED WITH THE KITE OR THE DEFAULT SECRET FOR YOUR ACCOUNT IF " "NO SECRET IS SET ON THE KITE." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "PROTOCOL" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "EXTERNAL (FRONTEND) PORT" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "INTERNAL (FREEDOMBOX) PORT" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "ENABLE SUBDOMAINS" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "DELETED CUSTOM SERVICE" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 #, fuzzy #| msgid "" #| "This service is available as a standard service. Please use the " @@ -5280,11 +5225,11 @@ msgstr "" "THIS SERVICE IS AVAILABLE AS A STANDARD SERVICE. PLEASE USE THE \"STANDARD " "SERVICES\" PAGE TO ENABLE IT. " -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "ADDED CUSTOM SERVICE" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "THIS SERVICE ALREADY EXISTS" @@ -5325,29 +5270,29 @@ msgstr "" "PROTOCOL/PORT COMBINATIONS THAT YOU ARE ABLE TO DEFINE HERE. FOR EXAMPLE, " "HTTPS ON PORTS OTHER THAN 443 IS KNOWN TO CAUSE PROBLEMS." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "WEB SERVER (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "SITE WILL BE AVAILABLE AT HTTP://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "WEB SERVER (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "SITE WILL BE AVAILABLE AT HTTPS://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "SECURE SHELL (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5393,8 +5338,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 #, fuzzy #| msgid "Restart Now" msgid "Restart" @@ -5444,6 +5389,39 @@ msgstr "" msgid "Shut Down Now" msgstr "SHUT DOWN NOW" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Enable Privoxy" +msgid "Privacy" +msgstr "ENABLE PRIVOXY" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 #, fuzzy #| msgid "" @@ -5498,7 +5476,7 @@ msgstr "PRIVOXY WEB PROXY" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "ACCESS {url} WITH PROXY {proxy} ON TCP{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "Quassel is an IRC application that is split into two parts, a \"core\" " @@ -5522,7 +5500,7 @@ msgstr "" "ONE OR MORE QUASSEL CLIENTS FROM A DESKTOP OR A MOBILE CAN BE USED TO " "CONNECT AND DISCONNECT FROM IT." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your DESKTOP AND MOBILE DEVICES ARE AVAILABLE." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 #, fuzzy #| msgid "Quassel IRC Client" msgid "IRC Client" @@ -5548,7 +5526,7 @@ msgstr "QUASSEL IRC CLIENT" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5558,19 +5536,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5629,7 +5607,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 #, fuzzy #| msgid "Configuration updated" msgid "Access rights configuration updated" @@ -5735,7 +5713,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5750,13 +5728,13 @@ msgstr "BRIDGE" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5765,31 +5743,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 #, fuzzy #| msgid "Network Time Server" msgid "Network File Storage" @@ -5879,19 +5857,19 @@ msgstr "KITE NAME" msgid "Action" msgstr "ACTIONS" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "FREEDOMBOX" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 #, fuzzy #| msgid "Add Service" msgid "Open Share" msgstr "ADD SERVICE" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 #, fuzzy #| msgid "Add Service" msgid "Group Share" @@ -5927,57 +5905,57 @@ msgstr "{name} DELETED." msgid "Error disabling share: {error_message}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 #, fuzzy #| msgid "Web Server" msgid "Web Search" msgstr "WEB SERVER" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 #, fuzzy #| msgid "Save Services" msgid "Safe Search" msgstr "SAVE SERVICES" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 #, fuzzy #| msgid "Mode" msgid "Moderate" msgstr "MODE" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -6159,14 +6137,14 @@ msgstr "BOOKMARKS (SHAARLI)" msgid "Shaarlier" msgstr "SHAARLI" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6175,107 +6153,107 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 #, fuzzy #| msgid "Service" msgid "Server" msgstr "SERVICE" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 #, fuzzy #| msgid "Server port" msgid "Server port number" msgstr "SERVER PORT" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 #, fuzzy #| msgid "Enable Shaarli" msgid "Sharing" msgstr "ENABLE SHAARLI" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 #, fuzzy #| msgid "Publish Key" msgid "Public share" msgstr "PUBLISH KEY" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 #, fuzzy #| msgid "This service already exists" msgid "A share with this name already exists." msgstr "THIS SERVICE ALREADY EXISTS" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -6318,30 +6296,30 @@ msgstr "" msgid "Add Share" msgstr "ADD SERVICE" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 #, fuzzy #| msgid "Edit User" msgid "Edit Share" msgstr "EDIT USER" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 #, fuzzy #| msgid "{name} deleted." msgid "Share deleted." msgstr "{name} DELETED." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6349,14 +6327,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 #, fuzzy #| msgid "Create User" msgid "Storage Snapshots" @@ -6464,7 +6442,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 #, fuzzy #| msgid "Delete %(name)s" msgid "Delete Snapshots" @@ -6516,65 +6494,65 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "packages not found" msgid "manually created" msgstr "PACKAGES NOT FOUND" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 #, fuzzy #| msgid "Create User" msgid "Manage Snapshots" msgstr "CREATE USER" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 #, fuzzy #| msgid "Configuration updated" msgid "Storage snapshots configuration updated" msgstr "CONFIGURATION UPDATED" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "ACTION ERROR: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 #, fuzzy #| msgid "Delete %(name)s" msgid "Deleted selected snapshots" msgstr "DELETE %(name)s" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6582,7 +6560,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "SECURE SHELL (SSH) SERVER" @@ -6621,14 +6599,6 @@ msgstr "" msgid "Fingerprint" msgstr "GPG FINGERPRINT" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -6643,7 +6613,7 @@ msgstr "LOGIN" msgid "Logged out successfully." msgstr "PASSWORD CHANGED SUCCESSFULLY." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6651,159 +6621,159 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 #, fuzzy #| msgid "reStore" msgid "Storage" msgstr "RESTORE" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 #, fuzzy #| msgid "repro service is running" msgid "The device is already unmounting." msgstr "REPRO SERVICE IS RUNNING" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 #, fuzzy #| msgid "This service already exists" msgid "The device is already mounted." msgstr "THIS SERVICE ALREADY EXISTS" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 #, fuzzy #| msgid "repro service is not running" msgid "The device is not mounted." msgstr "REPRO SERVICE IS NOT RUNNING" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid directory name." msgstr "INVALID HOSTNAME" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 #, fuzzy #| msgid "Download directory" msgid "Path is not a directory." msgstr "DOWNLOAD DIRECTORY" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 #, fuzzy #| msgid "Download directory" msgid "Directory" msgstr "DOWNLOAD DIRECTORY" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 #, fuzzy #| msgid "Add Service" msgid "Share" msgstr "ADD SERVICE" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6839,7 +6809,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6857,33 +6827,33 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, fuzzy, python-brace-format #| msgid "Error setting time zone: {exception}" msgid "Error expanding partition: {exception}" msgstr "ERROR SETTING TIME ZONE: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 #, fuzzy #| msgid "Password changed successfully." msgid "Partition expanded successfully." msgstr "PASSWORD CHANGED SUCCESSFULLY." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6891,7 +6861,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6903,22 +6873,22 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 #, fuzzy #| msgid "Installation" msgid "Administer Syncthing application" msgstr "INSTALLATION" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 #, fuzzy #| msgid "" #| "Tor is an anonymous communication system. You can learn more about it " @@ -6939,7 +6909,7 @@ msgstr "" "THE " "TOR BROWSER." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, fuzzy, python-brace-format #| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." msgid "" @@ -6947,42 +6917,42 @@ msgid "" "TCP port 9050." msgstr "A TOR SOCKS PORT IS AVAILABLE ON YOUR %(box_name)s ON TCP PORT 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 #, fuzzy #| msgid "Tor Hidden Service" msgid "Tor Onion Service" msgstr "TOR HIDDEN SERVICE" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "TOR BRIDGE RELAY" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "TOR RELAY PORT AVAILABLE" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "OBFS3 TRANSPORT REGISTERED" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "OBFS4 TRANSPORT REGISTERED" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "ACCESS URL {url} ON TCP{kind} VIA TOR" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "CONFIRM TOR USAGE AT {url} ON TCP{kind}" @@ -7098,13 +7068,13 @@ msgstr "HIDDEN SERVICE" msgid "Ports" msgstr "PORT" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "AN ERROR OCCURRED DURING CONFIGURATION." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error configuring app: {error}" @@ -7172,14 +7142,14 @@ msgstr "" msgid "Transmission" msgstr "TRANSMISSION BITTORRENT" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, the blogs and wikis will be available from /IKIWIKI." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -7209,12 +7179,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7222,8 +7192,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -7231,30 +7201,30 @@ msgstr "" msgid "Software Update" msgstr "SOFTWARE UPGRADES" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox Manual" msgid "FreedomBox Updated" msgstr "FREEDOMBOX MANUAL" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution update started" msgstr "AUTOMATIC UPGRADES DISABLED" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7438,57 +7408,57 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "AUTOMATIC UPGRADES ENABLED" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "ERROR WHEN CONFIGURING UNATTENDED-UPGRADES: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "AUTOMATIC UPGRADES ENABLED" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "AUTOMATIC UPGRADES DISABLED" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Distribution upgrade enabled" msgstr "AUTOMATIC UPGRADES ENABLED" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution upgrade disabled" msgstr "AUTOMATIC UPGRADES DISABLED" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "UPGRADE PROCESS STARTED." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "STARTING UPGRADE FAILED." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Starting distribution upgrade test." msgstr "AUTOMATIC UPGRADES ENABLED" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7496,15 +7466,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "USERS AND GROUPS" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "CHECK LDAP ENTRY \"{search_item}\"" @@ -7524,25 +7494,25 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 #, fuzzy #| msgid "Administrator Account" msgid "Authorization Password" msgstr "ADMINISTRATOR ACCOUNT" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Show password" msgid "Invalid password." msgstr "SHOW PASSWORD" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 #, fuzzy #| msgid "" #| "Select which services should be available to the new user. The user will " @@ -7563,13 +7533,13 @@ msgstr "" "ABLE TO LOG IN TO ALL SERVICES. THEY CAN ALSO LOG IN TO THE SYSTEM THROUGH " "SSH AND HAVE ADMINISTRATIVE PRIVILEGES (SUDO)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "CREATING LDAP USER FAILED." -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" @@ -7589,45 +7559,45 @@ msgstr "" "SYSTEM WITHOUT USING A PASSWORD. YOU MAY ENTER MULTIPLE KEYS, ONE ON EACH " "LINE. BLANK LINES AND LINES STARTING WITH # WILL BE IGNORED." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "RENAMING LDAP USER FAILED." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "FAILED TO REMOVE USER FROM GROUP." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "FAILED TO ADD USER TO GROUP." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "FAILED TO ADD USER TO GROUP." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "CHANGING LDAP USER PASSWORD FAILED." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "FAILED TO ADD NEW USER TO ADMIN GROUP." -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, fuzzy, python-brace-format #| msgid "Failed to obtain certificate for domain {domain}: {error}" msgid "Failed to restrict console access: {error}" msgstr "FAILED TO OBTAIN CERTIFICATE FOR DOMAIN {domain}: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "USER ACCOUNT CREATED, YOU ARE NOW LOGGED IN" @@ -7644,12 +7614,12 @@ msgstr "SAVE PASSWORD" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "CREATE USER" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "DELETE USER" @@ -7694,17 +7664,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "USERS" @@ -7737,34 +7707,34 @@ msgstr "" msgid "Save Changes" msgstr "SAVE CHANGES" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "USER %(username)s CREATED." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "USER %(username)s UPDATED." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "EDIT USER" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "USER {user} DELETED." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "DELETING LDAP USER FAILED." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "CHANGE PASSWORD" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "PASSWORD CHANGED SUCCESSFULLY." @@ -8125,7 +8095,7 @@ msgstr "DELETE CONNECTION" msgid "Server deleted." msgstr "{name} DELETED." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8134,7 +8104,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8143,28 +8113,28 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 #, fuzzy #| msgid "Address" msgid "WordPress" msgstr "ADDRESS" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Wiki and Blog" msgid "Website and Blog" @@ -8182,7 +8152,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8195,7 +8165,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8203,11 +8173,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -8260,119 +8230,113 @@ msgstr "" msgid "Finished: {name}" msgstr "SERVICE DISABLED: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing custom services" -msgid "Error running apt-get" -msgstr "EXISTING CUSTOM SERVICES" - -#: plinth/package.py:389 +#: plinth/package.py:348 #, fuzzy #| msgid "Installation" msgid "installing" msgstr "INSTALLATION" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 #, fuzzy #| msgid "Setting unchanged" msgid "media change" msgstr "SETTING UNCHANGED" -#: plinth/package.py:395 +#: plinth/package.py:354 #, fuzzy, python-brace-format #| msgid "Configuration" msgid "configuration file: {file}" msgstr "CONFIGURATION" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install" msgid "Installing app" msgstr "INSTALL" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error installing app: {error}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error updating app: {error}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Applications" msgid "App installed." msgstr "APPLICATIONS" -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "LAST UPDATE" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install" msgid "Uninstalling app" msgstr "INSTALL" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error uninstalling app: {error}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Applications" msgid "App uninstalled." msgstr "APPLICATIONS" -#: plinth/setup.py:451 +#: plinth/setup.py:452 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8441,62 +8405,62 @@ msgstr "INSTALLATION" msgid "Service %(service_name)s is not running." msgstr "SERVICE DISCOVERY SERVER IS NOT RUNNING" -#: plinth/templates/base.html:30 -#, fuzzy, python-format -#| msgid "Plinth administrative interface for the %(box_name)s" -msgid "Core functionality and web interface for %(box_name)s" -msgstr "PLINTH ADMINISTRATIVE INTERFACE FOR THE %(box_name)s" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 #, fuzzy #| msgid "Apps" msgid " Apps" msgstr "APPS" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "APPS" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 #, fuzzy #| msgid "System" msgid " System" msgstr "SYSTEM" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "SYSTEM" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "CHANGE PASSWORD" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 #, fuzzy #| msgid "Shut Down Now" msgid "Shut down" msgstr "SHUT DOWN NOW" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "LOG OUT" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 #, fuzzy #| msgid "Language" msgid "Select language" msgstr "LANGUAGE" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "LOG IN" @@ -8785,6 +8749,38 @@ msgstr "" msgid "Gujarati" msgstr "" +#, fuzzy +#~| msgid "Enable Dynamic DNS" +#~ msgid "Enable DNSSEC" +#~ msgstr "ENABLE DYNAMIC DNS" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "FIREWALL DAEMON IS NOT RUNNING. PLEASE RUN IT. FIREWALL COMES ENABLED BY " +#~ "DEFAULT ON %(box_name)s. ON ANY DEBIAN BASED SYSTEM (SUCH AS " +#~ "%(box_name)s) YOU MAY RUN IT USING THE COMMAND 'SERVICE FIREWALLD START' " +#~ "OR IN CASE OF A SYSTEM WITH SYSTEMD 'SYSTEMCTL START FIREWALLD'." + +#, fuzzy +#~| msgid "Mode" +#~ msgid "Migrate" +#~ msgstr "MODE" + +#, fuzzy +#~| msgid "Existing custom services" +#~ msgid "Error running apt-get" +#~ msgstr "EXISTING CUSTOM SERVICES" + +#, fuzzy, python-format +#~| msgid "Plinth administrative interface for the %(box_name)s" +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "PLINTH ADMINISTRATIVE INTERFACE FOR THE %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "NETWORK CONNECTIONS" diff --git a/plinth/locale/fr/LC_MESSAGES/django.po b/plinth/locale/fr/LC_MESSAGES/django.po index bb860d9b7..0e7cb78c4 100644 --- a/plinth/locale/fr/LC_MESSAGES/django.po +++ b/plinth/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: French calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1063,23 +1056,23 @@ msgstr "" "cette application. Les utilisateurs ayant cet accès pourront utiliser toutes " "les collections." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Utilisation des collections de livres électroniques calibre" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Bibliothèque de livres numériques" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Nom de la collection" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1088,7 +1081,7 @@ msgstr "" "caractères _ . et - sans espaces sont autorisés. Exemple : " "Ma_Bibliotheque_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Une collection portant ce nom existe déjà." @@ -1137,20 +1130,20 @@ msgstr "Ouvrir la collection %(library)s" msgid "Delete library %(library)s" msgstr "Supprimer la collection %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Collection créée." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Une erreur est survenue pendant la création de la collection." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} supprimé." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "La suppression de {name} a échoué : {error}" @@ -1201,7 +1194,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Administration du serveur" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1209,18 +1202,18 @@ msgstr "" "Cette page vous permet de modifier certains paramètres généraux comme le nom " "de machine, le nom de domaine, la page d’accueil du serveur web, etc." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Configuration générale" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Configurer" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1341,48 +1334,48 @@ msgstr "" "Les journaux contiennent des informations sur qui a accédé au système, ainsi " "que des informations de débogage sur différents services" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Erreur lors de la définition du nom de machine : {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Nom de machine configuré" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Erreur lors de la définition du nom de domaine : {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Nom de domaine configuré" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" "Erreur lors du changement de page d’accueil du serveur web : {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Page d’accueil du serveur web modifiée" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Erreur lors du changement de mode avancé : {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Les applications et fonctionnalités avancées seront affichées" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Les applications et les fonctionnalités avancées seront masquées" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1395,7 +1388,7 @@ msgstr "" "peuvent l’utiliser afin de mettre en relation des participants pour qui cela " "aurait été impossible autrement." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ejabberd qui peuvent l’utiliser en reportant les détails " "fournis ici dans leur configuration." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "Assistant de VoIP" @@ -1470,11 +1463,11 @@ msgstr "Erreur lors de la modification du fuseau horaire : {exception}" msgid "Time zone set" msgstr "Fuseau horaire modifié" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge est un client BitTorrent avec une interface utilisateur web." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1483,16 +1476,16 @@ msgstr "" "il est fortement recommandé de le modifier immédiatement après l’activation " "du service." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Téléchargement de fichiers avec les applications BitTorrent" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Client web pour BitTorrent" @@ -1621,7 +1614,7 @@ msgstr "Résultat" msgid "Diagnostic Test" msgstr "Test de diagnostic" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1633,7 +1626,7 @@ msgstr "" "Et ceci empêchera d’autres utilisateurs de découvrir les services proposés " "par cette {box_name}." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1651,7 +1644,7 @@ msgstr "" "d’assigner votre nom DNS à la nouvelle IP, de sorte que si quelqu’un sur " "Internet demande votre nom DNS, il obtiendra bien votre adresse IP courante." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1664,11 +1657,11 @@ msgstr "" "d’actualisation sur freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Client DNS dynamique" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Nom de domaine dynamique" @@ -1802,7 +1795,7 @@ msgstr "Ce champ est requis." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1857,7 +1850,7 @@ msgstr "Connexion refusée par le serveur" msgid "Already up-to-date" msgstr "Déjà à jour" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1865,7 +1858,7 @@ msgstr "" "XMPP est un protocole de communication ouvert et standardisé. Vous pouvez " "lancer et configurer ici votre serveur XMPP, appelé ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientutilisateur disposant d’un " "compte sur la {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn ou " "bien configurez un serveur externe." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Serveur de discussion" @@ -2018,7 +2011,7 @@ msgstr "" "Vous pouvez configurer le domaine de votre système sur la page Configurer." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -2029,7 +2022,7 @@ msgstr "" "aux clients de courriel d’accéder à votre boîte mel via les protocoles IMAP " "et POP3. Rspamd se charge des pourriels." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2041,7 +2034,7 @@ msgstr "" "Plusieurs FAI limitent aussi les courriels sortants. Certains retirent cette " "limite après une requête explicite. Voir le manuel pour plus de précisions." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2057,7 +2050,7 @@ msgstr "" "« postmaster » sont créés automatiquement, pointant vers le premier compte " "administrateur." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2065,7 +2058,7 @@ msgstr "" "L’appli Roundcube propose une " "interface Web pour accéder à vos courriels." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2196,7 +2189,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "Hôte/Cible/Valeur" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2208,7 +2201,7 @@ msgstr "" "Garder un pare-feu activé et correctement configuré réduit le risque des " "menaces provenant d’Internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Pare-feu" @@ -2228,53 +2221,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port {name} ({details}) non disponible pour les réseaux externes" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Le démon de pare-feu est arrêté. Veuillez le démarrer. Dans la configuration " -"d’origine de la %(box_name)s, le pare-feu est activé. Sur les systèmes basés " -"sur Debian (comme la %(box_name)s), vous pouvez démarrer le pare-feu en " -"utilisant la commande « service firewalld start » ou dans le cas d’un " -"système avec systemd, « systemctl start firewalld »." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Service/Port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Activé" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Désactivé" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Permis" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Permis (en interne uniquement)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Permis (en externe uniquement)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Bloqué" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2284,13 +2263,13 @@ msgstr "" "service, il est automatiquement permis par le pare-feu, si vous le " "désactivez, il est automatiquement désactivé dans le pare-feu." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Avancé" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2344,7 +2323,7 @@ msgstr "Démarrer la configuration initiale" msgid "Setup Complete" msgstr "Configuration initiale terminée" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2363,7 +2342,7 @@ msgstr "" "en ligne de commande ou l’un des nombreux clients graphiques existants. " "Partagez ainsi votre code source avec d’autres, tout autour du monde." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2371,68 +2350,68 @@ msgstr "" "Pour en apprendre plus sur l’utilisation de Git, consultez ce tutoriel Git." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Accès aux dépôts Git en lecture et en écriture" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Hébergement Git simple" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Adresse du dépôt invalide." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Nom de dépôt invalide." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Nom du dépôt à créer, ou adresse (URL) d’un dépôt existant pour l’importer." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Description du dépôt" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Paramètre optionnel, pour affichage dans Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Propriétaire du dépôt" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Dépôt privé" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Ne permet l’accès à ce dépôt qu’aux utilisateurs autorisés." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Un dépôt existe déjà avec ce nom." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Nom du dépôt" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "Une chaîne alpha-numérique qui identifie de manière unique le dépôt." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Branche par défaut" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb affiche cette branche comme branche par défaut." @@ -2476,19 +2455,19 @@ msgstr "Supprimer le dépôt Git %(name)s" msgid "Delete this repository permanently?" msgstr "Supprimer définitivement ce dépôt ?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Dépôt créé." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Une erreur est survenue pendant la création du dépôt." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Dépôt modifié." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Modifier le dépôt" @@ -2866,7 +2845,7 @@ msgstr "À propos de la {box_name}" msgid "{box_name} Manual" msgstr "Manuel {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2878,7 +2857,7 @@ msgstr "" "fournit de l’anonymat en envoyant du trafic chiffré sur un réseau distribué " "actionné par des volontaires partout sur la planète." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2886,7 +2865,7 @@ msgstr "" "Vous trouverez plus d’informations à propos d’I2P sur le site web de leur projet." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2894,19 +2873,19 @@ msgstr "" "L’interface web fournie vous guidera dans les étapes de configuration lors " "de votre première visite." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Gestion de l’application I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Réseau d’anonymisation" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "Serveur mandataire I2P" @@ -2952,7 +2931,7 @@ msgstr "" "un réseau de pair à pair. Téléchargez des fichiers en ajoutant des torrents " "ou en créant un nouveau torrent pour partager un fichier." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2963,7 +2942,7 @@ msgstr "" "fonctionnalités de blogue habituelles telles que les commentaires et les " "flux RSS." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2978,15 +2957,15 @@ msgstr "" "utilisateurs dans la configuration des utilisateurs." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki et blogue" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Consultation et modification des applications de wiki" @@ -3043,41 +3022,41 @@ msgstr "" "commentaires, ainsi que l’historique des révisions. Voulez-vous supprimer " "définitivement ce wiki ou blogue ?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Wiki {name} créé." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Échec de la création du wiki : {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Blogue {name} créé." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Échec de la création du blogue : {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} supprimé." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Échec de la suppression de {title} : {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted est un serveur pour Gobby, un éditeur de texte collaboratif." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3088,11 +3067,11 @@ msgstr "" "Gobby et installez-le. Lancez ensuite Gobby, sélectionnez « Connect to " "Server » et saisissez le nom de domaine de la {box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Serveur Gobby" @@ -3140,7 +3119,7 @@ msgstr "Salle de visio Janus" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Information de licence JavaScript" @@ -3160,7 +3139,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Client de discussion" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3175,7 +3154,7 @@ msgstr "" "chaque domaine disponible. Elle le fait en prouvant qu’elle est propriétaire " "du domaine auprès de l’autorité de certification « Let’s Encrypt »." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3189,15 +3168,15 @@ msgstr "" "fr/repository/\">conditions d’utilisation de Let’s Encrypt avant " "d’utiliser ce service." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let’s Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Certificats de chiffrement" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Test impossible : aucun domaine n’est configuré." @@ -3262,7 +3241,7 @@ msgstr "" "Aucun domaine n’a été configuré. Configurez des " "domaines pour pouvoir obtenir leurs certificats." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3271,36 +3250,36 @@ msgstr "" "Le certificat du domaine {domain} a été révoqué. Cette modification peut " "nécessiter quelques instants avant de prendre effet." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" "La révocation du certificat pour le domaine {domain} a échoué : {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Le certificat pour le domaine {domain} a été obtenu avec succès" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "L’obtention du certificat pour le domaine {domain} a échoué : {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Le certificat pour le domaine {domain} a été supprimé" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" "La suppression du certificat pour le domaine {domain} a échoué : {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3318,7 +3297,7 @@ msgstr "" "un serveur Matrix donné peuvent converser avec des utilisateurs sur tous les " "autres serveurs Matrix grâce la fédération." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3328,7 +3307,7 @@ msgstr "" "Installez pour cela l’application Coturn ou " "bien configurez un serveur externe." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3435,7 +3414,7 @@ msgstr "" "valide. Rendez-vous sur Let’s Encrypt " "pour en obtenir un." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3449,7 +3428,7 @@ msgstr "" "web de type wiki, pour prendre des notes ou pour collaborer sur des projets " "entre amis." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3464,7 +3443,7 @@ msgstr "" "vous rendant sur la page Special:CreateAccount." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3472,12 +3451,12 @@ msgstr "" "Toute personne ayant le lien vers ce wiki peut le consulter. Seuls les " "utilisateurs connectés avec leur compte peuvent y apporter des modifications." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3562,35 +3541,35 @@ msgstr "" "Échec de la mise à jour du mot passe. Veuillez choisir un mot de passe plus " "sûr" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Inscriptions publiques activées" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Inscriptions publiques désactivées" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Mode privé activé" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Mode privé désactivé" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Thème par défaut modifié" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Nom de domaine modifié" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Nom de site modifié" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3603,11 +3582,11 @@ msgstr "" "au serveur, vous devez disposer d’un client Minetest." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Bac à sable cubique" @@ -3661,7 +3640,7 @@ msgstr "" msgid "Address" msgstr "Adresse" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3850,7 +3829,7 @@ msgstr "Secure Shell" msgid "Services" msgstr "Services" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3859,7 +3838,7 @@ msgstr "" "le Wi-Fi ou le protocole PPPoE. Partage de cette connexion avec d’autres " "appareils du réseau local." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3867,7 +3846,7 @@ msgstr "" "Les périphériques gérés par d’autres méthodes pourraient ne pas être " "disponibles pour être configurés ici." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Réseau" @@ -4310,7 +4289,7 @@ msgstr "Modifier la connexion" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Modifier" @@ -4415,7 +4394,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Méthode" @@ -4431,7 +4410,7 @@ msgstr "Serveur DNS" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Défaut" @@ -4444,7 +4423,7 @@ msgid "This connection is not active." msgstr "Cette connexion n’est pas active." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Sécurité" @@ -5041,7 +5020,7 @@ msgstr "Connexion {name} supprimée." msgid "Failed to delete connection: Connection not found." msgstr "Échec de suppression de la connexion : connexion introuvable." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -5059,20 +5038,20 @@ msgstr "" "d’accéder au reste d’Internet au travers de la {box_name} pour une sécurité " "et un anonymat accrus." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Connexion aux services VPN" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Réseau privé virtuel" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5084,63 +5063,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" -"Migration vers la cryptographie ECC (Cryptographie basée sur les Courbes " -"Elliptiques)" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Votre installation OpenVPN utilise actuellement le protocole de " -"cryptographie RSA. La migration vers la Cryptographie basée sur les Courbes " -"Elliptiques (Elliptic Curve Cryptography), plus moderne, accélère " -"l’établissement de la connexion et améliore la sécurité. Cette opération est " -"irréversible. Cela ne devrait prendre que quelques minutes sur la plupart " -"des mini-ordinateurs SBC (Single Board Computers)." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Toutes les nouvelles installations de OpenVPN sur %(box_name)s utiliseront " -"la Cryptographie des Courbes Elliptiques (ECC) par défaut. Nous recommandons " -"de migrer aussi vite que possible." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Attention : Les profils client existants seront invalidés par cette " -"opération. Tous les utilisateurs de OpenVPN sur %(box_name)s devront " -"télécharger leurs nouveaux profils. Des clients OpenVPN compatibles avec la " -"cryptographie ECC devront être utilisés pour se connecter à ce serveur." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Migration" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Pour vous connecter au réseau privé virtuel VPN de la %(box_name)s, vous " @@ -5150,18 +5087,19 @@ msgstr "" "pour connaître les clients recommandés et leurs instructions de " "configuration." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Le profil est propre à chaque utilisateur de la %(box_name)s. Gardez-le " "secret." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Télécharger mon profil" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5175,18 +5113,18 @@ msgstr "" "reste de l’Internet. Cela se produit en général dans les situations " "suivantes :" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "La {box_name} est derrière un pare-feu avec des restrictions." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "La {box_name} est connectée à un réseau (sans fil) que vous ne contrôlez pas." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5194,7 +5132,7 @@ msgstr "" "Votre FAI ne vous fournit pas d’adresse IP externe, mais une connexion " "Internet via une traduction d’adresses réseau (NAT)." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5202,11 +5140,11 @@ msgstr "" "Votre FAI ne vous fournit pas une adresse IP statique, elle change à chaque " "fois que vous vous connectez à Internet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Votre FAI limite les connexions entrantes." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5222,23 +5160,23 @@ msgstr "" "a>. Il se pourrait que dans le futur, l’utilisation de la {box_name} d’un " "ami pour cela soit également proposée." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Visibilité publique" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "Domaine PageKite" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Domaine du serveur" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5246,31 +5184,31 @@ msgstr "" "Choisissez votre serveur pagekite. Saisissez « pagekite.net » pour utiliser " "le serveur pagekite.net par défaut." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Port serveur" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Port de votre serveur pagekite (par défaut : 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Nom Kite" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Exemple : monpc.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Nom Kite invalide" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite secret" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5278,35 +5216,35 @@ msgstr "" "Un secret associé au kite ou le secret par défaut de votre compte si aucun " "secret n’est défini sur ce kite." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protocole" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "port externe (du frontal)" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "port interne (de la freedombox)" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Activer les sous-domaines" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Service personnalisé supprimé" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Ce service est déjà disponible sous forme standard." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Service personnalisé ajouté" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Ce service existe déjà" @@ -5344,29 +5282,29 @@ msgstr "" "définition. Par exemple, l’utilisation de ports autre que 443 pour le " "protocole HTTPS est connu pour causer des problèmes." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Serveur web (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Le site sera accessible sur http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Serveur web (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Le site sera accessible sur https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Shell sécurisé (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5418,8 +5356,8 @@ msgstr "" "Une installation ou une mise à niveau est en cours. Il est préférable " "d’attendre la fin de l’opération avant d’éteindre ou de redémarrer." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Redémarrer" @@ -5469,6 +5407,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Éteindre immédiatement" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5512,7 +5483,7 @@ msgstr "Serveur mandataire web" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Accéder à l’URL {url} avec le mandataire {proxy} sur tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5529,7 +5500,7 @@ msgstr "" "toujours en ligne sur IRC. Un ou plusieurs clients Quassel sur ordinateur ou " "sur mobile peuvent ensuite se connecter ou se déconnecter du « cœur »." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile sont disponibles pour " "téléchargement." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "Client IRC" @@ -5554,7 +5525,7 @@ msgstr "Client IRC" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5571,7 +5542,7 @@ msgstr "" "cliente compatible. Tous les utilisateur disposant d’un compte sur la " "{box_name} ont accès à Radicale." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5582,12 +5553,12 @@ msgstr "" "charge l’ajout d’événements ou de contacts, opérations qui doivent être " "réalisées avec un client dédié." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Agenda et carnet d’adresses" @@ -5663,7 +5634,7 @@ msgstr "" "recherche pour afficher la liste de vos agendas et carnets d’adresses " "existants." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Configuration des droits d’accès mise à jour" @@ -5759,7 +5730,7 @@ msgstr "" "a> pour suivre différents sites internet. Lors de l’ajout d’un fil, activez " "l’authentification et utilisez les identifiants de {box_name}." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Lecture et abonnement à des flux d’actualités" @@ -5772,7 +5743,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "Générateur de fil RSS" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5780,7 +5751,7 @@ msgstr "" "Samba permet de partager des fichiers et des répertoires entre la FreedomBox " "et d’autres machines de votre réseau local." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5794,11 +5765,11 @@ msgstr "" "smb://{hostname}.local (sur Linux et Mac). Vous pourrez choisir parmi trois " "types de partages : " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Partage ouvert : accessible par tout le monde sur votre réseau local." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5806,7 +5777,7 @@ msgstr "" "Partage de groupe : accessible uniquement aux utilisateurs de la FreedomBox " "qui sont membres du groupe freedombox-share." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5814,15 +5785,15 @@ msgstr "" "Partage de dossier personnel : chaque utilisateur du groupe freedombox-share " "a son propre espace privé." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Accès aux partages privés" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Stockage de fichiers réseau" @@ -5911,15 +5882,15 @@ msgstr "Nom du partage" msgid "Action" msgstr "Action" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "Disque du système FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Ouvrir un partage" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Partage de groupe" @@ -5945,7 +5916,7 @@ msgstr "Partage désactivé." msgid "Error disabling share: {error_message}" msgstr "Erreur lors de la désactivation du partage : {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5954,7 +5925,7 @@ msgstr "" "privée. Il rassemble et affiche les résultats de plusieurs moteurs de " "recherche." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5962,41 +5933,41 @@ msgstr "" "Searx peut être utilisé pour éviter le pistage et le profilage fait par les " "moteurs de recherche. Par défaut il ne stocke aucun cookie." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Recherches sur le Web" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Recherche web" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Recherche sûre" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Choisissez le filtre de famille à appliquer par défaut à vos résultats de " "recherche." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Modéré" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Strict" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Permettre l’accès public" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Permettre l’utilisation de cette application à n’importe qui parvenant à y " @@ -6183,7 +6154,7 @@ msgstr "Signets" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6193,7 +6164,7 @@ msgstr "" "votre trafic Internet. Il peut être utilisé pour contourner les problèmes de " "filtrage ou de censure d’Internet." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6207,7 +6178,7 @@ msgstr "" "mandataire, et leurs flux de données seront chiffrés et transmis vers " "l’extérieur au travers du serveur Shadowsocks." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6216,44 +6187,44 @@ msgstr "" "l’URL de mandataire SOCKS5 sur votre appareil, navigateur ou application " "avec l’URL http://adresse_freedombox:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Mandataire Socks5" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Recommandé" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Serveur" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Nom ou adresse IP du serveur" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Numéro de port du serveur" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Mot de passe utilisé pour chiffrer les données. Doit correspondre au mot de " "passe du serveur." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" "Méthode de chiffrement. Doit correspondre à celle qui a été configurée sur " "le serveur." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6262,15 +6233,15 @@ msgstr "" "« Partages » vous permet de partager des fichiers et répertoires de votre " "{box_name} sur Internet avec des groupes d’utilisateurs bien définis." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Partages" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Nom du partage" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6278,29 +6249,29 @@ msgstr "" "Une chaîne alpha-numérique en minuscules qui identifie de manière unique le " "partage. Par exemple : media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Chemin du partage" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Chemin d’un répertoire sur ce serveur que vous souhaitez partager." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Partage public" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" "Les fichiers de ce répertoire seront accessible à toute personne possédant " "le lien vers ce partage." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Groupes d’utilisateurs autorisés à consulter les fichiers du partage :" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6308,11 +6279,11 @@ msgstr "" "Les utilisateurs des groupes sélectionnés pourront lire les fichiers du " "partage." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Un partage existe déjà avec ce nom." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" "Les partages peuvent être soit publics soit partagés avec au moins un groupe" @@ -6350,19 +6321,19 @@ msgstr "Partage créé." msgid "Add Share" msgstr "Ajouter un partage" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Partage modifié." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Modifier le partage" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Partage supprimé." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6373,7 +6344,7 @@ msgstr "" "utilisés pour ramener le système à un état précédent connu pour être " "fonctionnel, dans le cas ou des changements non désirés ont été appliqués." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6385,7 +6356,7 @@ msgstr "" "instantanés plus anciens seront supprimés automatiquement en fonction du " "paramétrage qui suit." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for sauvegardes car ils sont forcément conservés sur la même partition. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Instantanés de disque" @@ -6500,7 +6471,7 @@ msgstr "Date" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Supprimer les instantanés" @@ -6554,58 +6525,58 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Revenir à l’instantané n° %(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "créé manuellement" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "historique" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Gestion des instantanés" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Instantané créé." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Configuration des instantanés de disque mise à jour" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Erreur lors de l’opération : {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Supprimer les instantanés sélectionnés" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" "L’instantané est en cours d’utilisation. Veuillez réessayer ultérieurement." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Retour à l’instantané n° {number} effectué." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Le système doit être redémarré pour terminer le retour en arrière." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Revenir à l’instantané" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6617,7 +6588,7 @@ msgstr "" "effectuer des tâches d’administration, copier des fichiers ou bien faire " "fonctionner d’autres services en utilisant de telles connexions." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Serveur Secure Shell (SSH)" @@ -6655,14 +6626,6 @@ msgstr "Algorithme" msgid "Fingerprint" msgstr "Empreinte" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "Authentification SSH par mot de passe désactivée." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "Authentification SSH par mot de passe activée." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Authentification unique" @@ -6675,7 +6638,7 @@ msgstr "S’identifier" msgid "Logged out successfully." msgstr "Déconnecté avec succès." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6687,109 +6650,109 @@ msgstr "" "d’utilisation, monter et démonter des médias amovibles, étendre la partition " "racine, etc." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Stockage" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} octets" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} Kio" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} Mio" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} Gio" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} Tio" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "L’opération a échoué." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "L’opération a été annulée." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Le périphérique est déjà en train d’être démonté." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" "L’opération n’est pas disponible par manque d’un pilote ou d’un outil adapté." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "L’opération ne s’est pas terminée." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" "L’opération réveillerait un disque qui se trouve dans un état de veille " "profond." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Tentative de démontage d’un périphérique en cours d’utilisation." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "L’opération a déjà été annulée." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Vous n’êtes pas autorisé à effectuer l’opération demandée." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Le périphérique est déjà monté." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Le périphérique n’est pas monté." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Vous n’êtes pas autorisé à utiliser l’option demandée." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Le périphérique est monté par un autre utilisateur." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Espace disque faible sur la partition système : {percent_used}% utilisés, " "{free_space} libres." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Espace disque faible" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Panne de disque imminente" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6799,39 +6762,39 @@ msgstr "" "Copiez toutes les données qui s’y trouvent tant qu’il est encore temps et " "remplacez le disque." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Nom de répertoire invalide." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Le répertoire n’existe pas." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Le chemin n’est pas un répertoire." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Le répertoire n’est pas lisible par l’utilisateur." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "L’utilisateur ne peut pas écrire dans le répertoire." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Répertoire" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Sous-répertoire (optionnel)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Partage" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Autre répertoire (indiquer ci-dessous)" @@ -6869,7 +6832,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Étendre la partition racine" @@ -6893,30 +6856,30 @@ msgstr "" "votre partition racine disposera de %(expandable_root_size)s d’espace disque " "supplémentaire." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Erreur lors de l’extension de la partition : {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Extension de la partition réalisée avec succès." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} peut être débranché en toute sécurité." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Le périphérique peut être débranché en toute sécurité." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Erreur lors de l’éjection du périphérique : {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6929,7 +6892,7 @@ msgstr "" "seront automatiquement répliquées aux autres appareils qui utilisent " "Syncthing." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6949,20 +6912,20 @@ msgstr "" "{box_name} n’est accessible qu’aux utilisateurs membres des groupes " "« admin » et « syncthing-access »." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Administration de l’application Syncthing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Synchronisation de fichiers" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6976,7 +6939,7 @@ msgstr "" "recommande l’utilisation du Navigateur Tor." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6985,40 +6948,40 @@ msgstr "" "Un port SOCKS pour Tor est accessible sur votre {box_name} pour les réseaux " "internes via le port TCP 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Service onion Tor" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Mandataire Socks Tor" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Relais Tor de type pont (« bridge relay »)" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Le port du relais Tor est disponible" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Abonné au transport obfs3" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Abonné au transport obfs4" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Accédez à l’URL {url} sur tcp{kind} via Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Confirmez l’utilisation de Tor pour {url} sur tcp{kind}" @@ -7140,11 +7103,11 @@ msgstr "Service Onion" msgid "Ports" msgstr "Ports" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Mise à jour de la configuration" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Erreur lors de la configuration de l’application : {error}" @@ -7208,7 +7171,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7219,7 +7182,7 @@ msgstr "" "n’importe quel appareil tout en restant au plus près du design d’une " "application de bureau complète." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7229,7 +7192,7 @@ msgstr "" "\"{users_url}\">n’importe quel utilisateur appartenant au groupe de " "lecteur de fil." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7238,11 +7201,11 @@ msgstr "" "ordinateur, saisissez l’URL tt-rss-app pour " "vous connecter." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Lecteur de flux d’informations" @@ -7250,14 +7213,14 @@ msgstr "Lecteur de flux d’informations" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Rechercher et installer les dernières mises à jour logicielles et les " "correctifs de sécurité." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7271,22 +7234,22 @@ msgstr "" "nécessaire, il est effectué à 2h00, rendant indisponible l’ensemble des " "applications pour une courte période." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Mise à jour du système" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox mise à jour" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Impossible de lancer la mise à niveau de la distribution" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7297,11 +7260,11 @@ msgstr "" "sont disponibles. Si activée, la mise à niveau automatique de la " "distribution sera retentée dans 24H." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Mise à niveau de la distribution démarrée" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7483,46 +7446,46 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Lancer le test de mise à niveau de la distribution" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" "Erreur lors de la configuration du système de mise à jour automatique " "« unattended-upgrades » : {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Mises à niveau automatiques activées" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Mises à niveau automatiques désactivées" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Mise à niveau de la distribution activée" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Mise à niveau de la distribution désactivée" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Mise à jour lancée." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Le lancement de la mise à niveau a échoué." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Mise à jour régulière des fonctionnalités activée." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Démarrage du test de mise à niveau de la distribution." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7533,7 +7496,7 @@ msgstr "" "Certaines applis demandent en outre que les comptes soient membres d’un " "groupe particulier pour pouvoir accéder à l’application." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7545,15 +7508,15 @@ msgstr "" "principale. En revanche, seuls les utilisateurs membres du groupe admin peuvent modifier les applications ou changer les paramètres système." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Utilisateurs et groupes" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Accès à tous les services et à la configuration du système" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Vérification de l’entrée LDAP « {search_item} »" @@ -7573,11 +7536,11 @@ msgstr "" "Requis. 150 caractères ou moins. Lettres anglaises, chiffres et @/./-/_ " "uniquement." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Mot de passe actuel" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7585,11 +7548,11 @@ msgstr "" "Veuillez saisir votre mot de passe de l’utilisateur « {user} » pour " "confirmer ces modifications de compte." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Mot de passe incorrect." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7604,12 +7567,12 @@ msgstr "" "peuvent également se connecter au système avec Secure Shell (SSH) et obtenir " "les privilèges d’administrateur (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "La création de l’utilisateur LDAP a échoué : {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "L’ajout du nouvel utilisateur au groupe {group} a échoué : {error}" @@ -7629,42 +7592,42 @@ msgstr "" "plusieurs clefs, une sur chaque ligne. Les lignes vides et celles commençant " "par # sont ignorées." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Le changement du nom de l’utilisateur LDAP a échoué." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Échec du retrait de l’utilisateur du groupe." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Échec de l’ajout de l’utilisateur au groupe." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Échec du paramétrage des clefs SSH." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Échec du changement de statut de l’utilisateur." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Le changement du mot de passe de l’utilisateur LDAP a échoué." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "L’ajout du nouvel utilisateur au groupe admin a échoué : {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" "La mise en place des restrictions d’accès à la console à échoué : {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Compte utilisateur créé, vous êtes maintenant connecté" @@ -7681,12 +7644,12 @@ msgstr "Sauvegarder le mot de passe" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Créer un utilisateur" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Supprimer Utilisateur" @@ -7728,13 +7691,19 @@ msgid "The following administrator accounts exist in the system." msgstr "Les comptes administrateurs suivants sont présents sur le système." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Veuillez supprimer ces comptes depuis la ligne de commande et rafraîchir " "cette page pour pouvoir créer un compte utilisable avec la %(box_name)s. " @@ -7744,7 +7713,7 @@ msgstr "" "étape." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Utilisateurs" @@ -7777,34 +7746,34 @@ msgstr "" msgid "Save Changes" msgstr "Appliquer les changements" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Utilisateur %(username)s créé." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Utilisateur %(username)s mis à jour." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Modification de l’utilisateur" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Utilisateur {user} supprimé." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "La suppression de l’utilisateur LDAP a échoué." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Changer Mot de Passe" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Le mot de passe a été changé." @@ -8147,7 +8116,7 @@ msgstr "Supprimer la connexion à un serveur" msgid "Server deleted." msgstr "Serveur supprimé." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8162,7 +8131,7 @@ msgstr "" "thèmes. L’interface d’administration et les pages Web produites sont " "compatibles avec les appareils mobiles." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8177,7 +8146,7 @@ msgstr "" "l’interface d’administration pour améliorer les URL de vos pages et de vos " "billets de blogue." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8188,7 +8157,7 @@ msgstr "" "href=\"/wordpress/wp-admin/\">page d’administration à vos favoris pour y " "accéder ultérieurement." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8199,12 +8168,12 @@ msgstr "" "la mise à jour de modules additionnels et de thèmes se fait à vos risques et " "périls." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Site web et blogue" @@ -8222,7 +8191,7 @@ msgstr "" "WordPress. N’activez cette option qu’après avoir réalisé la configuration " "initiale de WordPress." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8245,7 +8214,7 @@ msgstr "" "recherche, de carte et de calendrier. Les photos peuvent être partagées " "unitairement avec d’autres en leur envoyant un lien direct." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8256,11 +8225,11 @@ msgstr "" "l’administrateur Zoph. Pour ajouter des utilisateurs ceux-ci doivent être " "créés à la fois sur la {box_name} et dans Zoph avec le même identifiant." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Photothèque" @@ -8314,96 +8283,92 @@ msgstr "Attente du démarrage de : {name}" msgid "Finished: {name}" msgstr "Terminé : {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Le paquet {expression} n’est pas disponible à l’installation" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Le paquet {package_name} est à la dernière version ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Erreur d’exécution d’« apt-get »" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "installation en cours" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "téléchargement en cours" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "changement de support" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "fichier de configuration : {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Aucune réponse du gestionnaire de paquets" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Installation de l’application" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Mise à jour de l’application" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Erreur lors de l’installation de l’appli : {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Erreur lors de la mise à jour de l’appli : {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Erreur lors de l’installation de l’appli : {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Erreur lors de la mise à jour de l’appli : {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "Application installée." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Application mise à jour" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Désinstallation de l’application" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Erreur lors de la désinstallation de l’appli : {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Erreur lors de la désinstallation de l’appli : {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "Application désinstallée." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Mise à jour des paquets de l’application" @@ -8464,53 +8429,54 @@ msgstr "Installation" msgid "Service %(service_name)s is not running." msgstr "Le service %(service_name)s n’est pas actif." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Fonctions de base et interface web de la %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Accueil" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Accueil" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Applis" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Applis" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Système" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Système" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Changer le mot de passe" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Éteindre" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Se déconnecter" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Choisir la langue" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "S’identifier" @@ -8804,6 +8770,81 @@ msgstr "avant la désinstallation de {app_id}" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Activer DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Activer les extensions de sécurité DNS (DNSSEC)" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Le démon de pare-feu est arrêté. Veuillez le démarrer. Dans la " +#~ "configuration d’origine de la %(box_name)s, le pare-feu est activé. Sur " +#~ "les systèmes basés sur Debian (comme la %(box_name)s), vous pouvez " +#~ "démarrer le pare-feu en utilisant la commande « service firewalld start » " +#~ "ou dans le cas d’un système avec systemd, « systemctl start firewalld »." + +#~ msgid "Migrate to ECC" +#~ msgstr "" +#~ "Migration vers la cryptographie ECC (Cryptographie basée sur les Courbes " +#~ "Elliptiques)" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Votre installation OpenVPN utilise actuellement le protocole de " +#~ "cryptographie RSA. La migration vers la Cryptographie basée sur les " +#~ "Courbes Elliptiques (Elliptic Curve Cryptography), plus moderne, accélère " +#~ "l’établissement de la connexion et améliore la sécurité. Cette opération " +#~ "est irréversible. Cela ne devrait prendre que quelques minutes sur la " +#~ "plupart des mini-ordinateurs SBC (Single Board Computers)." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Toutes les nouvelles installations de OpenVPN sur %(box_name)s " +#~ "utiliseront la Cryptographie des Courbes Elliptiques (ECC) par défaut. " +#~ "Nous recommandons de migrer aussi vite que possible." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Attention : Les profils client existants seront invalidés par " +#~ "cette opération. Tous les utilisateurs de OpenVPN sur %(box_name)s " +#~ "devront télécharger leurs nouveaux profils. Des clients OpenVPN " +#~ "compatibles avec la cryptographie ECC devront être utilisés pour se " +#~ "connecter à ce serveur." + +#~ msgid "Migrate" +#~ msgstr "Migration" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "Authentification SSH par mot de passe désactivée." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Authentification SSH par mot de passe activée." + +#~ msgid "Error running apt-get" +#~ msgstr "Erreur d’exécution d’« apt-get »" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Fonctions de base et interface web de la %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Connexions réseau" diff --git a/plinth/locale/gl/LC_MESSAGES/django.po b/plinth/locale/gl/LC_MESSAGES/django.po index 0c2741d86..ba3776b73 100644 --- a/plinth/locale/gl/LC_MESSAGES/django.po +++ b/plinth/locale/gl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-01-18 12:32+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Galician calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1025,20 +1018,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1076,24 +1069,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1189,47 +1182,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Configurar a páxina de inicio do servidor web" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1237,7 +1230,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1467,11 +1460,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1583,7 +1576,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1638,13 +1631,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1766,14 +1759,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1781,7 +1774,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1791,13 +1784,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1924,7 +1917,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1932,7 +1925,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1952,61 +1945,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2052,7 +2036,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2063,73 +2047,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2173,19 +2157,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2480,7 +2464,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2488,31 +2472,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2549,14 +2533,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2565,15 +2549,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2627,41 +2611,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2669,11 +2653,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2719,7 +2703,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2737,7 +2721,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2747,7 +2731,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2755,15 +2739,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2826,41 +2810,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2870,14 +2854,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2958,7 +2942,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2966,7 +2950,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2975,18 +2959,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3057,35 +3041,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3094,11 +3078,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3143,7 +3127,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3304,19 +3288,19 @@ msgstr "" msgid "Services" msgstr "Descubrimento de servizo" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3662,7 +3646,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3767,7 +3751,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3783,7 +3767,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3796,7 +3780,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4334,7 +4318,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4345,20 +4329,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4368,61 +4352,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4431,33 +4383,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4466,87 +4418,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4580,29 +4532,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4644,8 +4596,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4687,6 +4639,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4718,7 +4701,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4729,7 +4712,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4749,7 +4732,7 @@ msgstr "" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4759,19 +4742,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4830,7 +4813,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4897,7 +4880,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4910,13 +4893,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4925,31 +4908,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5027,17 +5010,17 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5065,51 +5048,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5262,14 +5245,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5278,97 +5261,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5405,26 +5388,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5432,14 +5415,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5533,7 +5516,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5581,59 +5564,59 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Manual" msgid "manually created" msgstr "Manual" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5641,7 +5624,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5674,14 +5657,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5694,7 +5669,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5702,143 +5677,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5872,7 +5847,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5890,30 +5865,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5921,7 +5896,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5933,20 +5908,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5955,47 +5930,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6093,11 +6068,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6150,31 +6125,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6182,12 +6157,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6195,35 +6170,35 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox Updated" msgstr "FreedomBox" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6375,51 +6350,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6427,15 +6402,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6453,21 +6428,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6476,12 +6451,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6497,41 +6472,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6548,12 +6523,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6591,17 +6566,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6632,34 +6607,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6970,7 +6945,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6979,7 +6954,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6988,26 +6963,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7021,7 +6996,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7034,7 +7009,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7042,11 +7017,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7096,108 +7071,104 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Produciuse un erro ao instalar o aplicativo: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Produciuse un erro ao instalar o aplicativo: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplicativo instalado." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Produciuse un erro ao instalar o aplicativo: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplicativo instalado." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7248,53 +7219,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/gu/LC_MESSAGES/django.po b/plinth/locale/gu/LC_MESSAGES/django.po index bc170825e..2a6446071 100644 --- a/plinth/locale/gu/LC_MESSAGES/django.po +++ b/plinth/locale/gu/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-01-18 12:32+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Gujarati calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Documentation" msgid "Name of the new library" msgstr "દસ્તાવેજીકરણ" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1085,20 +1078,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1143,24 +1136,24 @@ msgstr "કોકપિટ" msgid "Server Administration" msgstr "સર્વર સંચાલન" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "સામાન્ય ગોઠવણી" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "ગોઠવો" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1267,49 +1260,49 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "હોસ્ટનું નામ સ્થાપિત કરતાં ભૂલ થઇ: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "હોસ્ટનું નામ સ્થાપિત કર્યું" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "ક્ષેત્રીય નામ સ્થાપિત કરતાં ભૂલ થઇ: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "ક્ષેત્રીય નામ સ્થાપિત કર્યું" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, fuzzy, python-brace-format #| msgid "Error setting hostname: {exception}" msgid "Error setting webserver home page: {exception}" msgstr "હોસ્ટનું નામ સ્થાપિત કરતાં ભૂલ થઇ: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, fuzzy, python-brace-format #| msgid "Error setting domain name: {exception}" msgid "Error changing advanced mode: {exception}" msgstr "ક્ષેત્રીય નામ સ્થાપિત કરતાં ભૂલ થઇ: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1317,7 +1310,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as થી ઉપલબ્ધ થશે. તેનો પહેલાથી નક્કી પાસવર્ડ 'deluge' છે, પરંતુ આ સેવા સક્રિય " "કાર્ય બાદ તુરંત જ આપે લોગ ઇન કરી ને તેને બદલી નાખવો જોઈએ." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "BitTorrent કાર્યક્રમોનો ઉપયોગ કરીને ફાઇલો ડાઉનલોડ કરો" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "અનરાધાર" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "બીટ ટોરેન્ટ વેબ ક્લાયન્ટ" @@ -1537,7 +1530,7 @@ msgstr "પરિણામ" msgid "Diagnostic Test" msgstr "તપાસકીય પરિક્ષણ" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, fuzzy, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1548,7 +1541,7 @@ msgstr "" "અન્ય લોકો માટે તમને ઇન્ટરનેટ પર શોધવા માટે મુશ્કેલ હોઈ શકે છે. આ અન્ય લોકો જે આ દ્વારા " "પ્રદાન કરવામાં આવે છે તે સેવાઓ શોધવાનું અટકાવશે {box_name}" -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1565,7 +1558,7 @@ msgstr "" "પર સોંપી દેશે, અને જો ઇન્ટરનેટમાંથી કોઈ વ્યક્તિ તમારા DNS નામ માટે પૂછે, તેઓને તમારા " "વર્તમાન IP સરનામા સાથે પ્રતિસાદ મળશે." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 #, fuzzy #| msgid "" #| "If you are looking for a free dynamic DNS account, you may find a free " @@ -1584,11 +1577,11 @@ msgstr "" "net અથવા તમે મફત અપડેટ URL આધારિત સેવાઓને અહીંથી શોધી શકો છો freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "ડાયનેમિક DNS ક્લાયન્ટ" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 #, fuzzy #| msgid "Domain Name" msgid "Dynamic Domain Name" @@ -1721,7 +1714,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1782,7 +1775,7 @@ msgstr "" msgid "Already up-to-date" msgstr "છેલ્લો સુધારો" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1790,7 +1783,7 @@ msgstr "" "XMPP એક ખુલ્લું અને પ્રમાણિત સંચાર પ્રોટોકોલ છે. અહીં તમે તમારા XMPP સર્વરને ચલાવો અને " "ગોઠવી શકો છો, જેને ઈઝબેબર્ડે કહેવાય છે." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, fuzzy, python-brace-format #| msgid "" #| "To actually communicate, you can use the XMPP ક્લાયન્ટ. જ્યારે સક્ષમ કરેલ હોય, ઈઝબેબર્ડ ઍક્સેસ કરી શકાય છે " "કોઇપણ દ્વારા વપરાશકર્તાઓ સાથે{box_name}પ્રવેશ." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ઈઝબેબર્ડ" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "ચેટ સર્વર" @@ -1941,14 +1934,14 @@ msgstr "" "દેખાશે username@%(domainname)s. તમે સિસ્ટમ પર તમારા ડોમેન સેટ કરી શકો છો રૂપરેખાંકિત કરો પાનું." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1956,7 +1949,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1966,13 +1959,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2109,7 +2102,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2120,7 +2113,7 @@ msgstr "" "છે {box_name}. ફાયરવૉલ સક્ષમ અને યોગ્ય રીતે રૂપરેખાંકિત રાખીને ઇન્ટરનેટથી સુરક્ષાના ભયને " "ઘટાડે છે." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "ફાયરવોલ" @@ -2140,52 +2133,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"ફાયરવોલ ડિમન ચાલી રહ્યું નથી. કૃપા કરીને તેને ચલાવો. ફાયરવોલ %(box_name)s પર મૂળભૂત " -"સક્ષમ કરેલું છે. કોઈપણ ડેબિયન આધારિત સિસ્ટમ પર(જેવી કે %(box_name)s) તમે આદેશનો ઉપયોગ " -"કરીને તેને ચલાવી શકો છો 'service firewalld start' અથવા systemd સાથે સિસ્ટમના " -"કિસ્સામાં 'systemctl start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "સેવા/પોર્ટ" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "સક્ષમ કરેલું" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "અક્ષમ કરેલું" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "પરવાનગી છે" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "પરવાનગી છે (ફક્ત આંતરિક)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "પરવાનગી છે (બાહ્ય માત્ર)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "અવરોધિત" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2194,13 +2174,13 @@ msgstr "" "ફાયરવૉલનું સંચાલન આપોઆપ છે. જ્યારે તમે સેવાને સક્ષમ કરો છો ત્યારે તેને ફાયરવૉલમાં પણ " "પરવાનગી છે અને જ્યારે તમે કોઈ સેવા અક્ષમ કરો છો ત્યારે તે ફાયરવૉલમાં પણ અક્ષમ થાય છે." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2248,7 +2228,7 @@ msgstr "સેટઅપ પ્રારંભ કરો" msgid "Setup Complete" msgstr "સેટઅપ પૂર્ણ" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2259,83 +2239,83 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository URL." msgstr "અમાન્ય હોસ્ટનું નામ" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository name." msgstr "અમાન્ય હોસ્ટનું નામ" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Documentation" msgid "Private repository" msgstr "દસ્તાવેજીકરણ" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Documentation" msgid "Name of the repository" msgstr "દસ્તાવેજીકરણ" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Setting unchanged" msgid "Default branch" msgstr "સેટિંગ યથાવત" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2383,19 +2363,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 #, fuzzy #| msgid "Documentation" msgid "Edit repository" @@ -2694,7 +2674,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2702,33 +2682,33 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 #, fuzzy #| msgid "Enable application" msgid "Manage I2P application" msgstr "એપ્લીકેશનને પ્રસ્થાપિત કરો" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2765,14 +2745,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2781,15 +2761,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2843,41 +2823,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2885,11 +2865,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2935,7 +2915,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2953,7 +2933,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2963,7 +2943,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2971,15 +2951,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3042,41 +3022,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3086,14 +3066,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -3176,7 +3156,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3184,7 +3164,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3193,18 +3173,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3279,49 +3259,49 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 #, fuzzy #| msgid "Application installed." msgid "Public registrations enabled" msgstr "એપ્લીકેશન પ્રસ્થાપિત થઇ ગઈ છે." -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 #, fuzzy #| msgid "Application installed." msgid "Public registrations disabled" msgstr "એપ્લીકેશન પ્રસ્થાપિત થઇ ગઈ છે." -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 #, fuzzy #| msgid "Application enabled" msgid "Private mode enabled" msgstr "એપ્લિકેશન સક્ષમ કરો" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 #, fuzzy #| msgid "Application disabled" msgid "Private mode disabled" msgstr "એપ્લિકેશન અક્ષમ છે" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 #, fuzzy #| msgid "Setting unchanged" msgid "Default skin changed" msgstr "સેટિંગ યથાવત" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "ક્ષેત્રીય નામ સ્થાપિત કર્યું" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "ક્ષેત્રીય નામ સ્થાપિત કર્યું" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3330,11 +3310,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3379,7 +3359,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3544,19 +3524,19 @@ msgstr "" msgid "Services" msgstr "સેવા પ્રકાર" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3905,7 +3885,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -4010,7 +3990,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -4026,7 +4006,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -4039,7 +4019,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4592,7 +4572,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4603,22 +4583,22 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Conversations" msgid "Connect to VPN services" msgstr "વાતચીત" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4628,61 +4608,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4691,33 +4639,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4726,87 +4674,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4840,29 +4788,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4906,8 +4854,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4949,6 +4897,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4980,7 +4959,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4991,7 +4970,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -5011,7 +4990,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5021,19 +5000,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5092,7 +5071,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -5163,7 +5142,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5176,13 +5155,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5191,31 +5170,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5293,17 +5272,17 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "ફ્રિડમબોક્ષ" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5333,51 +5312,51 @@ msgstr "એપ્લિકેશન અક્ષમ છે" msgid "Error disabling share: {error_message}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5530,14 +5509,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5546,97 +5525,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5673,26 +5652,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5700,14 +5679,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5801,7 +5780,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5849,60 +5828,60 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Last update" msgid "manually created" msgstr "છેલ્લો સુધારો" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 #, fuzzy msgid "Storage snapshots configuration updated" msgstr "DNSSEC ગોઠવણીને સુધારેલી શરુ કરો" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5910,7 +5889,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5947,14 +5926,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5967,7 +5938,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5975,145 +5946,145 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid directory name." msgstr "અમાન્ય હોસ્ટનું નામ" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6147,7 +6118,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6165,30 +6136,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6196,7 +6167,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6208,20 +6179,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6230,47 +6201,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6370,13 +6341,13 @@ msgstr "ડાયનેમિક DNS સેવા" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "General Configuration" msgid "Updating configuration" msgstr "સામાન્ય ગોઠવણી" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6433,14 +6404,14 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -6451,17 +6422,17 @@ msgstr "" "સાથે{box_name} લૉગિન દ્વારા ઍક્સેસ કરી શકાય છે. સંવેદનશીલ માહિતી અને વ્યવસ્થાપનની " "ક્ષમતાઓ એડમિન ગ્રૂપના વપરાશકર્તાઓ માટે મર્યાદિત છે." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6469,12 +6440,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6482,37 +6453,37 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox Updated" msgstr "ફ્રિડમબોક્ષ" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "User registrations disabled" msgid "Distribution update started" msgstr "વપરાશકર્તા રજીસ્ટ્રેશન અક્ષમ છે" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6674,55 +6645,55 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "વપરાશકર્તા રજીસ્ટ્રેશન અક્ષમ છે" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "User registrations disabled" msgid "Distribution upgrade disabled" msgstr "વપરાશકર્તા રજીસ્ટ્રેશન અક્ષમ છે" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "User registrations disabled" msgid "Starting distribution upgrade test." msgstr "વપરાશકર્તા રજીસ્ટ્રેશન અક્ષમ છે" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6730,15 +6701,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6758,23 +6729,23 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Show password" msgid "Invalid password." msgstr "પાસવર્ડ બતાવો" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6783,12 +6754,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6804,41 +6775,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6855,12 +6826,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6898,17 +6869,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6939,34 +6910,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7299,7 +7270,7 @@ msgstr "ઇન્ટરનેટ સાથે સીધો જોડાણ." msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7308,7 +7279,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7317,26 +7288,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7350,7 +7321,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7363,7 +7334,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7371,11 +7342,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7427,112 +7398,108 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "એપ્લિકેશન્સ ઇન્સ્ટોલ કરો" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {string}{details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {string}{details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "એપ્લીકેશન પ્રસ્થાપિત થઇ ગઈ છે." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "છેલ્લો સુધારો" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "એપ્લિકેશન્સ ઇન્સ્ટોલ કરો" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {string}{details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "એપ્લીકેશન પ્રસ્થાપિત થઇ ગઈ છે." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7583,57 +7550,58 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 #, fuzzy #| msgid "BitTorrent Web Client" msgid " Apps" msgstr "બીટ ટોરેન્ટ વેબ ક્લાયન્ટ" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 #, fuzzy #| msgid "Language" msgid "Select language" msgstr "ભાષા" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -7908,6 +7876,24 @@ msgstr "" msgid "Gujarati" msgstr "" +#~ msgid "Enable DNSSEC" +#~ msgstr "DNSSEC ને શરુ કરો" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "ક્ષેત્રીય નામ વ્યવસ્થાની સુરક્ષા વૃદ્ધીઓ ને શરુ કરો" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "ફાયરવોલ ડિમન ચાલી રહ્યું નથી. કૃપા કરીને તેને ચલાવો. ફાયરવોલ %(box_name)s પર " +#~ "મૂળભૂત સક્ષમ કરેલું છે. કોઈપણ ડેબિયન આધારિત સિસ્ટમ પર(જેવી કે %(box_name)s) તમે આદેશનો " +#~ "ઉપયોગ કરીને તેને ચલાવી શકો છો 'service firewalld start' અથવા systemd સાથે " +#~ "સિસ્ટમના કિસ્સામાં 'systemctl start firewalld'." + #, fuzzy #~| msgid "Disabled" #~ msgid "Disable" diff --git a/plinth/locale/hi/LC_MESSAGES/django.po b/plinth/locale/hi/LC_MESSAGES/django.po index 36a6f705b..37a15efd7 100644 --- a/plinth/locale/hi/LC_MESSAGES/django.po +++ b/plinth/locale/hi/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-01-18 12:32+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Hindi calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Name of the share" msgid "Name of the new library" msgstr "शेयर का नाम" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 #, fuzzy #| msgid "A share with this name already exists." msgid "A library with this name already exists." @@ -1151,24 +1144,24 @@ msgstr "" msgid "Delete library %(library)s" msgstr "साइट हटाएं %(site)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 #, fuzzy #| msgid "Archive created." msgid "Library created." msgstr "पुरालेख बनाया गया." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 #, fuzzy #| msgid "An error occurred during configuration." msgid "An error occurred while creating the library." msgstr "कॉंफ़िगरेशन के दौरान कूछ त्रुटि हुई." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} हटा गया है." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "{name} नहीं हटा गया है: {error}" @@ -1218,24 +1211,24 @@ msgstr "कॉकपिट" msgid "Server Administration" msgstr "सर्वर एडमिनिस्ट्रेशन" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "सामान्य कॉन्फ़िगरेशन" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "कॉन्फ़िगर करें" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1354,49 +1347,49 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "{exception}: होस्ट नाम सेट करने में एरर" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "होस्ट नाम सेट हो गया" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "{exception}: डोमेन नाम सेट करने में एरर" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "डोमेन नाम सेट हो गया है" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, fuzzy, python-brace-format #| msgid "Error setting hostname: {exception}" msgid "Error setting webserver home page: {exception}" msgstr "{exception}: होस्ट नाम सेट करने में एरर" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, fuzzy, python-brace-format #| msgid "Error setting domain name: {exception}" msgid "Error changing advanced mode: {exception}" msgstr "{exception}: डोमेन नाम सेट करने में एरर" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1404,7 +1397,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as freedns.afraid." "org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "डायनेमिक डिएनएस ग्राहक" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 #, fuzzy #| msgid "Domain Name" msgid "Dynamic Domain Name" @@ -1813,7 +1806,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1882,7 +1875,7 @@ msgstr "कनेक्शन हटाएँ" msgid "Already up-to-date" msgstr "अंतिम अपडेट" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1890,7 +1883,7 @@ msgstr "" "एक्सएमरपिपि एक खुला और मानकीकृत संचार प्रोटोकॉल है. यहां आप आपना एक्सएमरपिपि सर्वर " "कॉंफ़िगर आैर चल सकते हैं, सर्वर का नाम एजाबेरड है." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, fuzzy, python-brace-format #| msgid "" #| "To actually communicate, you can use the web " @@ -1908,19 +1901,19 @@ msgstr "" "ग्राहक. सक्षम होने पर एजाबेरड कोई यूसर एक {box_name} " "लोगिन से उपयोग कर सकते हैं." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "एजाबेरड" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "चाट सर्वर" @@ -2036,14 +2029,14 @@ msgstr "" "दिखेगा username@%(domainname)s. आपका डोमेन सिसटेम पर सेटअप कर सकता है कॉन्फ़िगर पेजॅ." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2051,7 +2044,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2061,13 +2054,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2210,7 +2203,7 @@ msgstr "पोर्ट" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2221,7 +2214,7 @@ msgstr "" "को नियंत्रित करता है. फ़ायरवॉल सक्षम और ठीक से कॉंफ़िगर रखते हुए इंटरनेट से सुरक्षा खतरे का " "जोखिम कम कर देता है." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "फ़ायरवॉल" @@ -2243,52 +2236,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"फ़ायरवॉल डेमन नहीं चल रहा है. इको चलिये. फ़ायरवॉल %(box_name)s पर डिफ़ॉल्ट से सक्षम " -"आता है. किसी डेबियन आधारित सिसटेम पर (%(box_name)s से तरह) आप इससे चल सकते है, 'सेवा " -"फायरवॉल शुरू' आदेश उपयेग कर या एक सिस्टमदि सिस्टम के साथ 'सिसटेमसिटिएल फायरवॉल शुरू' " -"उपयेग कर." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "सर्विस/पोर्ट" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "सक्षम किया गया है" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "अक्षम किया गया है" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "अनुमति दिया गया है" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "अनुमति दिया गया है (सिर्फ आंतरिक)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "अनुमति दिया गया है (सिर्फ बाहरी)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "अवरुद्ध" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2297,13 +2277,13 @@ msgstr "" "फ़ायरवॉल की ऑपरेशन स्वचालित है. जब आप एक सेवा सक्षम करते है, फ़ायरवॉल में भी अनुमति है और " "जब एक सेवा अक्षम करते है, फ़ायरवॉल में भी अक्षम करेगा." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2356,7 +2336,7 @@ msgstr "सटअप शुरु करें" msgid "Setup Complete" msgstr "सेटअप पूरा हो गया" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2367,75 +2347,75 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository URL." msgstr "अमान्य होस्टनाम" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository name." msgstr "अमान्य होस्टनाम" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Create User" msgid "Private repository" msgstr "यूसर बनाये" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 #, fuzzy #| msgid "A share with this name already exists." msgid "A repository with this name already exists." msgstr "इस नाम का एक शयर पहले से मौजूद है." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Name of the share" msgid "Name of the repository" msgstr "शेयर का नाम" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 #, fuzzy #| msgid "" #| "A lowercase alpha-numeric string that uniquely identifies a share. " @@ -2445,13 +2425,13 @@ msgstr "" "कोई लोअरकेस अल्फ़ा-सांख्यिक स्ट्रिंग जो विशिष्ट रूप से एक शेयर की पहचान करता है. उदाहरण:" "media." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Default" msgid "Default branch" msgstr "डिफ़ॉल्ट" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2506,21 +2486,21 @@ msgstr "विकी और ब्लॉग हटाईये %(name)s%(box_name)s Wiki." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 #, fuzzy #| msgid "Enable application" msgid "Manage I2P application" msgstr "एप्लिकेशन सक्षम करें" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "गुमनामी नेटवर्क" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 #, fuzzy #| msgid "Web Proxy" msgid "I2P Proxy" @@ -2933,7 +2913,7 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 #, fuzzy #| msgid "" #| "ikiwiki is a simple wiki and blog application. It supports several " @@ -2951,7 +2931,7 @@ msgstr "" "होने पर, ब्लॉग्स और विकि /इकिविकि/ (एक बार बनाए गए) पर " "उपलब्ध होंगे." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2964,15 +2944,15 @@ msgstr "" "विकी संपादितकर सकते है. वह युज़र कॉन्फ़िगरेशन पर " "आपको यह अनुमति बदल सकता और नया युज़रसॅ को जोडं सकता है." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "इकिविकि" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "विकि और ब्लॉग" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "विकी एप्लिकेशन को देखें और संपादित करें" @@ -3028,43 +3008,43 @@ msgstr "" "यह कार्य सब पोस्ट, पेज और टिप्पणियां निकाल देगी, संशोधन इतिहास भी. यह ब्लॉग और विकी " "हमेशा से हटा करें?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "विकी बनाया है {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "विकी नहीं बना सकता है:{error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "ब्लॉग बनाया है {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "ब्लॉग नहीं बना सकता है: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, fuzzy, python-brace-format #| msgid "{name} deleted." msgid "{title} deleted." msgstr "{name} हटा गया है." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, fuzzy, python-brace-format #| msgid "Could not delete {name}: {error}" msgid "Could not delete {title}: {error}" msgstr "{name} नहीं हटा गया है: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "इन्फिनोटेड़ गोबी के एक सर्वर है, एक सहयोगी टेक्स्ट संपादक." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3075,11 +3055,11 @@ msgstr "" "डाउनलोड और इंस्टॉल करें. फिर गोबी शुरु करें, \"सर्वर से कनेक्ट\" चुनें और {box_name} " "कर डोमेन नाम दर्ज करें." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "इन्फिनोटेड़" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "गोबी सर्वर" @@ -3125,7 +3105,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "जावास्क्रिप्ट लाइसेंस जानकारी" @@ -3145,7 +3125,7 @@ msgstr "जेएसएक्ससि" msgid "Chat Client" msgstr "चैट क्लाइंट" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3159,7 +3139,7 @@ msgstr "" "प्रमाणपत्र सेटअप प्राप्त कर सकता है. {box_name} यह लेटस एंक्रिप्ट का डोमेन का एकमात्र " "मालिक सताबित करके एेसा करता है." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3171,15 +3151,15 @@ msgstr "" "\"https://letsencrypt.org/repository/\"> लेटस एंक्रिप्ट ग्राहक समझौते इस " "सिरविस उपयोग करने से पहले." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "लेटस एंक्रिप्ट" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "प्रमाण पत्र" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3247,7 +3227,7 @@ msgstr "" "कोई डोमेन कॉंफ़िगर नहीं किया गया है. डोमेन कॉंफ़िगर करें उंहें के लिए प्रमाणपत्र प्राप्त करने के " "लिये." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3256,34 +3236,34 @@ msgstr "" "डोमेन पर प्रमाणपत्र कामयाबी सेवापस ले लिया गया{domain}. यह कुछ समय को प्रभावी करने के " "लिए ले सकता है." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "डोमेन पर प्रमाणपत्र कामयाबी से वापस नहीं ले लिया गया{domain}:{error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "डोमेन के लिए प्रमाणपत्र कामयाबी से प्राप्त किया {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "डोमेन के लिए प्रमाणपत्र कामयाबी से नहीं प्राप्त किया {domain}:{error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "डोमेन के लिए प्रमाणपत्र कामयाबी से हटाया गया {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "डोमेन के लिए प्रमाणपत्र नहीं हटाया गया {domain}:{error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3298,14 +3278,14 @@ msgstr "" "मल्टीपल डिवाइस सिंक्रनाइज़इज़ाशिन और काम करने के लिए फोन नंबर की ज़रुरत नहीं है. मैट्रिक्स " "सर्वर पर यूसरसॅ सारे मैट्रिक्स सर्वर के लेग से बात कर सकते है फ़ेडरेशिन उपयोग कर." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "मैट्रिक्स सिनापसॅ" @@ -3401,7 +3381,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3413,7 +3393,7 @@ msgstr "" "से-तरह वेबसाइट होस्ट करने के लिये, नोट्स लेने के लिये या दोस्तों के साथ प्रोजेक्ट्स पर कास कर " "सकते है." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3426,7 +3406,7 @@ msgstr "" "उपयोग करके. फिर और यूसर अकाउंट मीडियाविकी खुद ही से बना सकते है यहां जा कर Special:CreateAccountपेज." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3434,12 +3414,12 @@ msgstr "" "किसी के साथ लिंक है, वह इस विकी पढ़ सकते हैं. सिर्फ लॉगइन किए गए यूसरसॅ ही सामग्री में " "परिवर्तन कर सकते हैं." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "मीडियाविकी" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "विकी" @@ -3523,41 +3503,41 @@ msgid "Password update failed. Please choose a stronger password" msgstr "" "डेटा एंक्रिप्ट करने के लिए पासवर्ड उपयोग किया गया . सर्वर पासवर्ड से मेल खाना चाहिए." -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "सार्वजनिक रेगीसट्रेशिन सक्षम किया" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "सार्वजनिक रेगीसट्रेशिन अक्षम किया" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "निजी मोड सक्षम किया" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "निजी मोड सक्षम किया" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 #, fuzzy #| msgid "Setting unchanged" msgid "Default skin changed" msgstr "सेटिंग स्थिर है" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "डोमेन नाम सेट हो गया है" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "डोमेन नाम सेट हो गया है" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3569,11 +3549,11 @@ msgstr "" "{box_name} पर चल सकवाते है, डिफ़ॉल्ट पोर्ट (३००००) पर. सर्वर से कनेक्ट करने के लिए, एक " "मैइनटेस्ट क्लायंटकी आवश्यकता है." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "मैइनटेस्ट" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "ब्लॉक सेंडबोक्स" @@ -3620,7 +3600,7 @@ msgstr "अक्षम होने पर खिलाड़ियों न msgid "Address" msgstr "ऍड्रेस" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3801,19 +3781,19 @@ msgstr "सुरक्षित शेल" msgid "Services" msgstr "सर्विस" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "नेटवर्क्‍स" @@ -4182,7 +4162,7 @@ msgstr "कनेक्शन संपादित करें" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "संपादन" @@ -4287,7 +4267,7 @@ msgstr "आईपीवी4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "तरीका" @@ -4303,7 +4283,7 @@ msgstr "डीएनएस सर्वर" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "डिफ़ॉल्ट" @@ -4316,7 +4296,7 @@ msgid "This connection is not active." msgstr "यह कनेक्शन सक्रिय नहीं है." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "सुरक्षा" @@ -4920,7 +4900,7 @@ msgstr "कनेक्शन {name} हटाया गया." msgid "Failed to delete connection: Connection not found." msgstr "कनेक्शन हटाने में विफल: कनेक्शन नहीं मिला." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4936,22 +4916,22 @@ msgstr "" "आंतरिक सर्विसस उपयोग करने के लिये. आप बाकी सब इंटरनेट {box_name} के जरिए उपयोग कर " "सकते हैं अगर अापको और सुरक्षा और गुमनामी चाहिये." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection Type" msgid "Connect to VPN services" msgstr "कनेक्शन टाइप" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "ओपन वीपीएन" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "वर्चुअल प्राइवेट नेटवर्क" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4962,45 +4942,11 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -#, fuzzy -#| msgid "Moderate" -msgid "Migrate" -msgstr "मॉडरेट" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "प्रोफ़ाइल" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, fuzzy, python-format #| msgid "" #| "To connect to %(box_name)s's VPN, you need to download a profile and feed " @@ -5011,8 +4957,8 @@ msgstr "प्रोफ़ाइल" #| "how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "%(box_name)s का वीपीएन से कनेक्ट करने के लिए, आपको एक प्रोफ़ाइल डाउनलोड करना चाहिये " @@ -5021,16 +4967,17 @@ msgstr "" "FreedomBox/Manual/OpenVPN\" title=\"%(box_name)s Manual - OpenVPN" "\">documentation देखें अनुशंसित क्लाइंट और उन्हें कॉन्फ़िगर करने के तरीके देखने के लिये." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "प्रोफ़ाइल हर %(box_name)s यूसर के लिए विशिष्ट है. इसे गुप्त रखें." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "मेरी प्रोफ़ाइल डाउनलोड करें" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5042,17 +4989,17 @@ msgstr "" "सीधा कनेक्शन नहीं है. इसके जरूरत है सिर्फ आपके {box_name} के सर्विसस बाकी इंटरनेट से पहुँच " "योग्य नहीं. इसमें इन स्थितियों को शामिल किया गया है:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} एक प्रतिबंधित फ़ायरवॉल के पीछे है." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "{box_name} एक (वायरलेस) रूटर से कनेक्टेड है जिसे आप नियंत्रित नहीं करते हैं." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5060,7 +5007,7 @@ msgstr "" "आपका ISP आपको एक बाहरी IP एड्रेस नहीं दता लेकिन NAT के माध्यम से इंटरनेट कनेक्शन प्रदान " "करता है." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5068,11 +5015,11 @@ msgstr "" "आपके ISP आपको एक स्थिर IP एड्रेस प्रदान नहीं करता है और आपके IP एड्रेस बदलाएग जब आप " "इंटरनेट से कनेक्ट होते हैं." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "आपके ISP आने वाले कनेक्शंसस को सीमित करता है." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, fuzzy, python-brace-format #| msgid "" #| "PageKite works around NAT, firewalls and IP-address limitations by using " @@ -5091,25 +5038,25 @@ msgstr "" "pagekite.net. भविष्य में अापका दोस्त का " "{box_name} इसके लिये उपयोग कर सकते हैं." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "पेजकइट" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "सार्वजनिक विसिबिलिटी" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 #, fuzzy #| msgid "PageKite Account" msgid "PageKite Domain" msgstr "पेजकईट अकाउंट" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "सर्वर डोमेन" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5117,58 +5064,58 @@ msgstr "" "अपने पेजकईटसर्वर चूनें. \"pagekite.net\" सेट करें डिफ़ॉल्ट pagekite.net सर्वर उपयोग करने " "के लिए." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "सर्वर पोर्ट" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "अपने पेजकईट सर्वर का पोर्ट (डिफ़ॉल्ट: ८०)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "कईट नाम" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "उदाहरण: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "अमान्य कईट नाम" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "कईट गुप्त" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" "एक कोई का सम्बंधित गुप्त या अपना अकाउंट का डिफ़ॉल्ट गुप्त अगर कोई रहस्य कईट पर सेट है." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "प्रोटोकॉल" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "बाहरी (फ्रंटेंड) पोर्ट" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "आंतरिक (फ्रीडमबॉकस) पोर्ट" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "सबडोमेन सक्षम करें" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "हटाई गई कस्टम सर्विस" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 #, fuzzy #| msgid "" #| "This service is available as a standard service. Please use the " @@ -5178,11 +5125,11 @@ msgstr "" "यह सर्विस एक मानक सर्विस के रूप में उपलब्ध है. इसे सक्षम करने के लिए \"मानक सर्विस\" पेज " "का उपयोग करें." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "जोड़ा गया कस्टम सर्विस" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "यह सर्विस पहले से मौजूद है" @@ -5223,29 +5170,29 @@ msgstr "" "पोर्ट संयोजन का समर्थन नहीं कर सकते है. उदाहरण के लिए, ४४३ के अलावा पोर्ट पर HTTPS " "समस्याओं का कारण बनता है." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "वेब सर्वर (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "साइट http://{0} पर उपलब्ध होगा" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "वेब सर्वर (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "साइटhttps://{0}पर उपलब्ध होगा" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "सुरक्षित शैल (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5291,8 +5238,8 @@ msgstr "" "अभी एक स्थापना या अपग्रेड चल रहा है. इसे शट डाउन या रीस्टार्ट करने से पहले इसे समाप्त " "होने तक प्रतीक्षा करें." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "रीस्टार्ट" @@ -5343,6 +5290,39 @@ msgstr "" msgid "Shut Down Now" msgstr "अब शट डाउन करें" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "प्रिवोक्सी" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5387,7 +5367,7 @@ msgstr "वेब प्रॉक्सी" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "{url} ऐकसेस करें प्रॉक्सी लेकर {proxy} टीसीपी पर{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5403,7 +5383,7 @@ msgstr "" "ताकि आप हमेशा ऑनलाइन रखते हुए और एक या अधिक क्वासेल क्लाइंट डेस्कटॉप या मोबाइल से इसेसे " "कनेक्ट और डिस्कनेक्ट करने के लिए उपयोग किया जा सकता है." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your मोबाइल से कनेक्ट होने के लिए क्लाइंट्स उपलब्ध " "हैं." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "क्वासेल" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "आईआरसी क्लाइंट" @@ -5427,7 +5407,7 @@ msgstr "आईआरसी क्लाइंट" msgid "Quasseldroid" msgstr "क्वासेलड्रोइड" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5446,19 +5426,19 @@ msgstr "" "org/clients/\">समर्थित क्लाइंट एप्लिकेशन कि जरुरत है. राडिकैल किसी {box_name} " "यूसर पहुंचा जा सकता है एक लॉगिन के साथ." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "राडिकैल" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "कैलेंडर और पता पुस्तिका" @@ -5540,7 +5520,7 @@ msgstr "" "(जैसे http://localhost:5232) और अपने यूसरनाम दर्ज करें. खोज बटन पर क्लिक करने से मौजूदा " "कैलेंडर और पता पुस्तिकाएं सूचीबद्ध होंगी." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "ऐकसेस अधिकार कॉंफ़िगरेशन अपडेट किया गया" @@ -5634,7 +5614,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "समाचार फ़ीड्स पढ़ें और सब्सक्राइब करें" @@ -5647,13 +5627,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5662,31 +5642,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 #, fuzzy #| msgid "Distributed File Storage" msgid "Network File Storage" @@ -5778,19 +5758,19 @@ msgstr "शेयर जोड़ा गया." msgid "Action" msgstr "एक्सआयन" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "फ्रीडमबोएक्स" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 #, fuzzy #| msgid "Add Share" msgid "Open Share" msgstr "शेयर जोड़ें" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 #, fuzzy #| msgid "Add Share" msgid "Group Share" @@ -5826,7 +5806,7 @@ msgstr "शेयर संपादित किया गया." msgid "Error disabling share: {error_message}" msgstr "एेरर इजेक्टिग्न डिवाइस: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5834,7 +5814,7 @@ msgstr "" "सिरएक्स एक गोपनीयता संमान इंटरनेट मेटा खोज इंजन है. यह विभिन्न खोज यन्त्र से परिणाम " "इकट्ठा और प्रदर्शन करता है." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5842,39 +5822,39 @@ msgstr "" "सिरएक्स खोज इंजन द्वारा ट्रैकिंग और प्रोफाइलिंग से बचने के लिए इस्तेमाल किया जा सकता है. " "यह डिफ़ॉल्ट से कोई कुकीज़ स्टोर नहीं करता है." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "वेब सरच किजिये" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "सिरएक्स" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "वेब खोज" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "सेफ खोज" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "अपने खोज परिणामों पर अप्लाई करने के लिए डिफ़ॉल्ट परिवार फ़िल्टर चूनिये." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "मॉडरेट" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "स्ट्रिक्ट" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -6057,7 +6037,7 @@ msgstr "बुकमार्क्स" msgid "Shaarlier" msgstr "शारली" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6066,7 +6046,7 @@ msgstr "" "शैडोवॉक्स एक हल्के और सुरक्षित सॉक्स 5 प्रॉक्सी है, आपके इंटरनेट यातायात रक्षा करने के लिये. " "यह इंटरनेट फ़िल्टरिंग और सेंसरशिप बाईपास करने के लिए इस्तेमाल किया जा सकता है." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6078,7 +6058,7 @@ msgstr "" "है. यह एक सॉक्स 5 प्रॉक्सी भी चला जाएगा. स्थानीय डिवाइसस इस प्रॉक्सी से कनेक्ट कर सकते " "हैं, और उनके डेटा एंक्रिप्टेड और शैडोवॉक्स सर्वर के माध्यम से प्रॉक्सी हो जाएगा." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6086,41 +6066,41 @@ msgstr "" "सेटअप के बाद शैडोवॉक्स का उपयोग करने के लिए,अपने डिवाइस, ब्राउज़र या एप्लिकेशन में सॉक्स5 " "प्रॉक्सी यूआरएल पर सेट करें http://freedombox_address:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "शाडोसोक्स" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "सोक्स5 प्रॉक्सी" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "अनुशंसित" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "सर्वर" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "सर्वर होस्ट नाम या IP एड्रेस" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "सर्वर पोर्ट नंबर" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "डेटा एंक्रिप्ट करने के लिए पासवर्ड उपयोग किया गया . सर्वर पासवर्ड से मेल खाना चाहिए." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "एंक्रिप्शन मेथोड. सर्वर सेटिंग पर मेल खाना चाहिए." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6129,15 +6109,15 @@ msgstr "" "शेयरिंग आपको अपने {box_name} पर फ़ाइलों और फ़ोल्डरों चुना गया यूसरस के साथ वेब पर साझा " "करने की अनुमति देता है." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "शेयरिंग" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "शेयर का नाम" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6145,31 +6125,31 @@ msgstr "" "कोई लोअरकेस अल्फ़ा-सांख्यिक स्ट्रिंग जो विशिष्ट रूप से एक शेयर की पहचान करता है. उदाहरण:" "media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "शयर करने के लिए पाथ" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "इस सर्वर पर किसी फ़ोल्डर का डिस्क पाथ है जो आप साझा करना चाहते हैं." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 #, fuzzy #| msgid "Publish Key" msgid "Public share" msgstr "चाबी प्रकाशित करें" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 #, fuzzy #| msgid "User groups who can read the files in the share" msgid "User groups that can read the files in the share:" msgstr "युसर समूह जो शयर में फ़ाइलें पढ़ सकते हैं" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 #, fuzzy #| msgid "" #| "Users who have these permissions will also be able to read the files in " @@ -6179,11 +6159,11 @@ msgid "" "share." msgstr "इन अनुमतियों वाले युसरस को शयर में फ़ाइलें भी पढ़ सकते हैं." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "इस नाम का एक शयर पहले से मौजूद है." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -6220,19 +6200,19 @@ msgstr "शेयर जोड़ा गया." msgid "Add Share" msgstr "शेयर जोड़ें" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "शेयर संपादित किया गया." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "शेयर संपादित करें" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "शेयर हटाया गया." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6242,7 +6222,7 @@ msgstr "" "को वापस रोल करने के लिए इस्तेमाल किया जा सकता है, एक पहले अच्छी स्थिति ज्ञात है अगर " "सिस्टम पर अवांछित बदलाव किया गया." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6250,7 +6230,7 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 #, fuzzy #| msgid "" #| "Snapshots work on btrfs file systems only and on the root partition only. " @@ -6264,7 +6244,7 @@ msgstr "" "स्नैपशॉट्स सिर्फ btrfs फाइल सिस्टम और रूट पार्टीशन पर काम करते हैं. स्नैपशॉट बैकअप के लिए " "प्रतिस्थापन नहीं है क्योंकि वे उसी पार्टीशन पर संग्रहित होते हैं. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "स्टोरेज स्नैपशॉटस" @@ -6363,7 +6343,7 @@ msgstr "तिथि" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "स्नैपशॉटस हटाएँ" @@ -6413,61 +6393,61 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "स्नैपशॉट से रोलबैक करें #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Archive created." msgid "manually created" msgstr "पुरालेख बनाया गया." -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "स्नैपशॉटस प्रबंधित करें" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "स्नैपशॉट बनाया गया है." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "स्टोरेज स्नैपशॉट कॉंफ़िगरेशन अपडेट किया गया" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "क्रिया त्रुटि: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 #, fuzzy #| msgid "Delete all the snapshots" msgid "Deleted selected snapshots" msgstr "सब स्नैपशॉटस हटाएँ" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "स्नैपशॉट #{number} पर वापस रोलबाक होगा." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "रोलबैक शुरु करने के लिए सिस्टम रीस्टार्ट करने का ज़रुरत है." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "स्नैपशॉट को रोलबैक करें" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6478,7 +6458,7 @@ msgstr "" "स्वीकार करने के लिये. एक अधिकार दिया गया रिमोट कंप्यूटर प्रशासन कार्य निष्पादित कर " "सकता है, फ़ाइलों की कॉपी कर सकता है या ऐसे कनेक्शंस का उपयोग करके अंय सर्विसस चलाएे." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "सुरक्षित शैल (SSH) सर्वर" @@ -6517,14 +6497,6 @@ msgstr "" msgid "Fingerprint" msgstr "SSH फिंगरप्रिंट" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "एकल साइन-ऑन" @@ -6539,7 +6511,7 @@ msgstr "लॉगिन" msgid "Logged out successfully." msgstr "पासवर्ड सफलतापूर्वक बदल गया." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6547,91 +6519,91 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "स्टोरेज" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} बाइट्स" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} किब" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} मेब" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} जिब" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} टीब" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "ऑपरेशन अनुत्तीर्ण हो गया." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "ऑपरेशन रद्द किया गया." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "यह डिवाइस पहले से अनमाउट किया जा रहा है." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "यह ऑपरेशन अनुपलब्ध है क्यैकि ड्राइवर/उपकरण टूल समर्थित नहीं है." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "ऑपरेशन टाइम आउट हो गया." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "यह ऑपरेशन गहरी नींद की स्थिति का डिस्क को जाग जाएगा." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "व्यस्त डिवाइस को अनमाउंट करने का प्रयास कर रहा है." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "ऑपरेशन पहले से रद्द किया गया." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "अनुरोधित ऑपरेशन करने के लिए अधिकृत नहीं है." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "यह डिवाइस पहले से माउंट किया गया." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "यह डिवाइस नहीं माउंट किया गया." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "अनुरोधित विकल्प का उपयोग करने की अनुमति नहीं है." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "किसी और यूसर ने डिवाइस माउंट किया गया है." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, fuzzy, no-python-format, python-brace-format #| msgid "" #| "Warning: Low space on system partition ({percent_used}% used, " @@ -6641,64 +6613,64 @@ msgstr "" "वार्निंग: सिस्टम पार्टीशन पर कम जगह ({percent_used}% उपयोग किया गया, " "{free_space} free)." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid directory name." msgstr "अमान्य होस्टनाम" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 #, fuzzy #| msgid "Download directory" msgid "Path is not a directory." msgstr "डायरेक्टरी डाउनलोड करें" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 #, fuzzy #| msgid "The device is mounted by another user." msgid "Directory is not readable by the user." msgstr "किसी और यूसर ने डिवाइस माउंट किया गया है." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 #, fuzzy #| msgid "Download directory" msgid "Directory" msgstr "डायरेक्टरी डाउनलोड करें" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 #, fuzzy #| msgid "Shared" msgid "Share" msgstr "साझा किया गया" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6737,7 +6709,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "रूट पारटिशन विस्तार करें" @@ -6757,30 +6729,30 @@ msgstr "" "आगे बढ़ने से पहले अपने डेटा का बैकअप करें. इस ऑपरेशन के बाद, %(expandable_root_size)s से " "अतिरिक्त खाली जगह आपके रूट पार्टीशन में उपलब्ध होगा." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "पार्टीशन का विस्तार करने में त्रुटि: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "पार्टीशन सफलतापूर्वक विस्तारित हुआ." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor}{drive_model} को सुरक्षित रूप से अनप्लग किया जा सकता है." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "डिवाइस सुरक्षित रूप से अनप्लग किया जा सकता है." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "एेरर इजेक्टिग्न डिवाइस: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6791,7 +6763,7 @@ msgstr "" "सिंक्रनाइज़ करने के लिए एक एप्लिकेशन है. सिंकतिन्ग चलते हए डिवाइसस पर किसी एक डिवाइस में " "फ़ाइलों का निर्माण, संशोधन, या हटाना ऑटोमेटिक दोहरा किया गया." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, fuzzy, python-brace-format #| msgid "" #| "Running Syncthing on {box_name} provides an extra synchronization point " @@ -6815,20 +6787,20 @@ msgstr "" "सेट एक फ़ोल्डर्स का एक अलग सेट का उपयोग करके सिंक्रनाइज़ किया जा सकता है. {box_name} " "पर वेब इंटरफेस सिर्फ \"एडमिन\" समूह के यूसकस के लिए उपलब्ध है." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "सिंकतिन्ग एप्लिकेशन का प्रशासन करें" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "सिंकतिन्ग" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "फ़ाइल सिंक्रनाइज़ेशन" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6841,7 +6813,7 @@ msgstr "" "टो प्रोजेक्ट सिफारिश की है कि आप टो ब्राउज़र उपयोग करें." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, fuzzy, python-brace-format #| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." msgid "" @@ -6849,42 +6821,42 @@ msgid "" "TCP port 9050." msgstr "एक टोर सॉक्स पोर्ट आपका %(box_name)s र उपलब्ध है, TCP पोर्ट ९०५० पर." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "टोर" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 #, fuzzy #| msgid "Tor Hidden Service" msgid "Tor Onion Service" msgstr "टोर हिडन सर्विस" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "टोर सोक्स प्रॉक्सी" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "टो ब्रिज रीले" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "टोर रीले पोर्ट उपलब्ध है" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 ट्रांसपोर्ट पंजीकृत" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 ट्रांसपोर्ट पंजीकृत" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "यूआरएल एक्सेस करें {url} टीसीपी पर {kind} टोर के माध्यम से" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "टोर उपयोग की पुष्टि करें {url} पर टीसीपी पर {kind}" @@ -7007,13 +6979,13 @@ msgstr "हिडन सर्विस" msgid "Ports" msgstr "पोर्टस" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "कॉंफ़िगरेशन के दौरान कूछ त्रुटि हुई." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -7083,7 +7055,7 @@ msgstr "" msgid "Transmission" msgstr "हस्तांतरण" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7093,7 +7065,7 @@ msgstr "" "से समाचार पढ़ने की अनुमति देने के लिए डिज़ाइन किया गया है, एक असली डेस्कटॉप एप्लिकेशन के " "जैसे." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Tiny Tiny RSS will be available from /" @@ -7107,7 +7079,7 @@ msgstr "" "माैजूद होते है. यह किसी एक {box_name} के सात लॉग इन " "कर सकता है." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 #, fuzzy #| msgid "" #| "When using a mobile or desktop application for Tiny Tiny RSS, use the URL " @@ -7119,11 +7091,11 @@ msgstr "" "टैनी टैनी आरएसएस का मोबाइल या डेस्कटॉप एप्लिकेशन उपयोग करते समय, यह यूआरएल/tt-rss-app कनेक्ट करने के लिए उपयोग करें." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "टिनी टिनी आरएसएस" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "समाचार फ़ीड रीडर" @@ -7131,12 +7103,12 @@ msgstr "समाचार फ़ीड रीडर" msgid "Tiny Tiny RSS (Fork)" msgstr "टैनी टैनी आरएसएस (फोर्क)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7144,8 +7116,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -7153,30 +7125,30 @@ msgstr "" msgid "Software Update" msgstr "सॉफ्टवेयर अपग्रेडस" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox Foundation" msgid "FreedomBox Updated" msgstr "फ्रीडमबाक्स फाउंडेशन" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution update started" msgstr "ऑटोमेटिक अपग्रेडस अक्षम किया गया" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7360,57 +7332,57 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "ऑटोमेटिक अपग्रेडस सक्षम किया गया" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "अनअटेंडेड-अपग्रेडस कॉन्फ़िगर करते समय त्रुटि: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "ऑटोमेटिक अपग्रेडस सक्षम किया गया" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "ऑटोमेटिक अपग्रेडस अक्षम किया गया" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Distribution upgrade enabled" msgstr "ऑटोमेटिक अपग्रेडस सक्षम किया गया" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution upgrade disabled" msgstr "ऑटोमेटिक अपग्रेडस अक्षम किया गया" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "अपग्रेड प्रक्रिया शुरू हुई." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "अपग्रेड प्रारंभ करना विफल रहा." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Starting distribution upgrade test." msgstr "ऑटोमेटिक अपग्रेडस सक्षम किया गया" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7418,15 +7390,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "यूसरस और समूह" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "सब सर्विसस और सिस्टम सेटिंग्स तक पहुंच" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "एलडीएपी प्रविष्टि चेक करें \"{search_item}\"" @@ -7446,25 +7418,25 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 #, fuzzy #| msgid "Administrator Password" msgid "Authorization Password" msgstr "व्यवस्थापक पासवर्ड" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Show password" msgid "Invalid password." msgstr "शो पासवर्ड" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 #, fuzzy #| msgid "" #| "Select which services should be available to the new user. The user will " @@ -7484,13 +7456,13 @@ msgstr "" "

एडमिन ग्रुप के यूसरस सब सर्विसस पर लॉग इन कर सकेगें. SSH के माध्यम से भी " "सिस्टम पर लॉग इन कर सकते है अाैर उनको प्रशासनिक विशेषाधिकार (sudo) है." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "एलडीएपी यूसर बनाना विफल रहा." -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" @@ -7510,45 +7482,45 @@ msgstr "" "बिना सिस्टम में प्रवेश करने की अनुमति देगा. आप एकाधिक कीज़ दर्ज कर सकते हैं, हर लाइन रक " "एक. खाली लाइनस या # से प्रारंभ होने वाले लाइनस अनदेखा कर दिया जाएगा." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "एलडीएपी यूसर का नाम बदलना विफल रहा." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "समूह से यूसर को हटाने में विफल." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "समूह से यूसर को जोड़ने में विफल." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "एसएसएच कीज़ सेट करने में असमर्थ." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "समूह से यूसर को जोड़ने में विफल." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "एलडीएपी यूसर का पासवर्ड बदलना विफल रहा." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "व्यवस्थापक समूह में नया यूसर जोड़ने में विफल." -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, fuzzy, python-brace-format #| msgid "Failed to restrict console access." msgid "Failed to restrict console access: {error}" msgstr "कंसोल एक्सेस प्रतिबंधित करने में विफल." -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "युसर अकाउंट बनाया, अब आप लॉगड इन हैं" @@ -7565,12 +7537,12 @@ msgstr "पासवर्ड सहेजें" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "यूसर बनाये" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "यूसर हटाइये" @@ -7615,17 +7587,17 @@ msgid "The following administrator accounts exist in the system." msgstr "सिस्टम में केवल व्यवस्थापक को नहीं हटा सकता." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "यूसरस" @@ -7659,34 +7631,34 @@ msgstr "" msgid "Save Changes" msgstr "बदलाव संचयित कीजिये" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "युसर %(username)s बनाया." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "युसर %(username)s अपडेट किया." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "यूसर संपादित करें" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "यूसर {user} हटाया." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "एलडीएपी यूसरको हटाने में असफल रहा." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "पासवर्ड बदलिये" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "पासवर्ड सफलतापूर्वक बदल गया." @@ -8054,7 +8026,7 @@ msgstr "कनेक्शन हटाएँ" msgid "Server deleted." msgstr "शेयर हटाया गया." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8063,7 +8035,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8072,28 +8044,28 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 #, fuzzy #| msgid "Address" msgid "WordPress" msgstr "ऍड्रेस" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Wiki and Blog" msgid "Website and Blog" @@ -8111,7 +8083,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8124,7 +8096,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8132,11 +8104,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -8189,114 +8161,108 @@ msgstr "" msgid "Finished: {name}" msgstr "सर्विस सक्षम किया गया:{name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing custom services" -msgid "Error running apt-get" -msgstr "मौजूदा कस्टम सर्विसस" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "इंस्टॉलिंग" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "डाउनलोडिंग" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "मीडिया बदलाव" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "कॉंफ़िगरेशन फ़ाइल: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "ऐप्लिकेशन इंस्टॉल करें" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता : {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता : {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "एप्लिकेशन इंस्टॉल हो गया." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "अंतिम अपडेट" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "ऐप्लिकेशन इंस्टॉल करें" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता : {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "एप्लिकेशन इंस्टॉल हो गया." -#: plinth/setup.py:451 +#: plinth/setup.py:452 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8368,54 +8334,54 @@ msgstr "इंस्टालेशन" msgid "Service %(service_name)s is not running." msgstr "सर्विस %(service_name)s नहीं चल रहा है." -#: plinth/templates/base.html:30 -#, fuzzy, python-format -#| msgid "Core funtionality and web interface for %(box_name)s" -msgid "Core functionality and web interface for %(box_name)s" -msgstr "%(box_name)s के लिए कोर फंक्शनलिटी और वेब इंटरफेस" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " होम" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "होम" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " ऐप्स" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "ऐप्स" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " सिस्टम" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "सिस्टम" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "पासवर्ड बदलें" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "शट डाउन" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "लॉग आउट" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "भाषा चुनें" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "लॉग इन" @@ -8699,6 +8665,39 @@ msgstr "" msgid "Gujarati" msgstr "" +#~ msgid "Enable DNSSEC" +#~ msgstr "डीएनएसएसईसि सक्षम करें" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "डॉमेन नाम सिस्टम सुरक्षा एक्सटेंशनस सक्षम करें" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "फ़ायरवॉल डेमन नहीं चल रहा है. इको चलिये. फ़ायरवॉल %(box_name)s पर डिफ़ॉल्ट से सक्षम " +#~ "आता है. किसी डेबियन आधारित सिसटेम पर (%(box_name)s से तरह) आप इससे चल सकते है, " +#~ "'सेवा फायरवॉल शुरू' आदेश उपयेग कर या एक सिस्टमदि सिस्टम के साथ 'सिसटेमसिटिएल " +#~ "फायरवॉल शुरू' उपयेग कर." + +#, fuzzy +#~| msgid "Moderate" +#~ msgid "Migrate" +#~ msgstr "मॉडरेट" + +#, fuzzy +#~| msgid "Existing custom services" +#~ msgid "Error running apt-get" +#~ msgstr "मौजूदा कस्टम सर्विसस" + +#, fuzzy, python-format +#~| msgid "Core funtionality and web interface for %(box_name)s" +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "%(box_name)s के लिए कोर फंक्शनलिटी और वेब इंटरफेस" + #~ msgid "Network Connections" #~ msgstr "नेटवर्क कनेक्शन्स" diff --git a/plinth/locale/hu/LC_MESSAGES/django.po b/plinth/locale/hu/LC_MESSAGES/django.po index 0d3948b3a..01687e9ab 100644 --- a/plinth/locale/hu/LC_MESSAGES/django.po +++ b/plinth/locale/hu/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Hungarian calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1051,23 +1044,23 @@ msgstr "" "alkalmazáshoz. Minden hozzáféréssel rendelkező felhasználó használhatja az " "összes könyvtárat." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Calibre e-könyvtárak használata" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "E-könyvtár" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Az új könyvtár neve" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 #, fuzzy #| msgid "" #| "Only letters of the English alphabet and numbers, without spaces or " @@ -1079,7 +1072,7 @@ msgstr "" "A könyvtár neve csak az angol ábécé betűit és számokat tartalmazhat, " "szóközök és különleges karakterek nélkül. Példa: Konyvtar_neve_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Már létezik ilyen nevű könyvtár." @@ -1127,20 +1120,20 @@ msgstr "Ugrás ebbe a könyvtárba: %(library)s" msgid "Delete library %(library)s" msgstr "%(library)s nevű könyvtár törlése" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Könyvtár létrehozva." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Hiba történt a könyvtár létrehozása közben." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} törölve." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "{name} nem törölhető: {error}" @@ -1188,7 +1181,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Szerver adminisztráció" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1196,18 +1189,18 @@ msgstr "" "Itt általános dolgokat állíthatsz be, például gazdagépnév, domainnév, " "webszerver kezdőoldala stb." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Általános beállítások" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Beállítások" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1322,47 +1315,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Hiba az állomásnév beállítása közben: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Állomásnév beállítva" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Hiba a domainnév beállítása közben: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Domainnév beállítva" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Hiba a webszerver kezdőoldalának beállítása közben: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Webszerver kezdőoldal beállítva" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Hiba a haladó módba váltás során: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Haladó szintű alkalmazások és funkciók megjelenítése" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Haladó szintű alkalmazások és funkciók elrejtése" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1374,7 +1367,7 @@ msgstr "" "más kommunikációs szerverek használhatják arra, hogy hívást hozzanak létre " "olyan felek között, akik egyébként nem tudnának kapcsolódni egymáshoz." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse vagy az ejabberd, az itt megadott részletekkel kell konfigurálni." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP-segéd" @@ -1447,11 +1440,11 @@ msgstr "Hiba az időzóna beállítása során: {exception}" msgid "Time zone set" msgstr "Időzóna beállítva" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "A Deluge egy webes felülettel rendelkező BitTorrent-kliens." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1459,16 +1452,16 @@ msgstr "" "Az alapértelmezett jelszó 'deluge', de a szolgáltatás engedélyezése után " "jelentkezz be és azonnal változtasd meg." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Fájlok letöltése BitTorrent-alkalmazások használatával" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Webes BitTorrent-kliens" @@ -1595,7 +1588,7 @@ msgstr "Eredmény" msgid "Diagnostic Test" msgstr "Ellenőrző teszt" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1607,7 +1600,7 @@ msgstr "" "Ez megakadályozza, hogy mások megtalálják a {box_name} által biztosított " "szolgáltatásokat." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1625,7 +1618,7 @@ msgstr "" "DNS-neved az új IP-címedhez, és ha valaki az Interneten lekérdezi a DNS-" "neved, válaszként az aktuális IP-címedet fogja megkapni." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1638,11 +1631,11 @@ msgstr "" "szolgáltatást a " "freedns.afraid.org címen." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Dinamikus DNS ügyfél" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Dinamikus domainnév" @@ -1773,7 +1766,7 @@ msgstr "Ezt a mezőt ki kell tölteni." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1828,7 +1821,7 @@ msgstr "A szerver visszautasította a kapcsolatot" msgid "Already up-to-date" msgstr "Már frissítve" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1836,7 +1829,7 @@ msgstr "" "Az XMPP egy nyílt és szabványos kommunikációs protokoll. Itt tudod futtatni " "és konfigurálni az XMPP-szerveredet, amit ejabberd-nek neveznek." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client felhasználó számára {box_name} " "felhasználónéven." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn alkalmazást " "vagy állíts be egy külső szervert." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Chat szerver" @@ -1988,7 +1981,7 @@ msgstr "" "fognak kinézni: username@%(domainname)s. Beállíthatod a rendszered " "domainnevét a Beállítások lapon." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1999,7 +1992,7 @@ msgstr "" "lehetővé teszi az e-mail kliensek hozzáférését a leveleidhez az IMAP és POP3 " "protokollokat használva, az Rspamd pedig a kéretlen levelek szűrését végzi." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2007,7 +2000,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2023,7 +2016,7 @@ msgstr "" "álnevek, mint pl. a \"postmaster\" az első admin felhasználóhoz tartozva " "automatikusan létrejönnek az alkalmazás telepítése során." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2031,7 +2024,7 @@ msgstr "" "Roundcube alkalmazás webes felületet " "biztosít a felhasználók számára e-mail eléréséhez." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2161,7 +2154,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "Állomás/Cél/Érték" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2172,7 +2165,7 @@ msgstr "" "hálózati forgalmát felügyeli. A folyamatosan aktív és megfelelően beállított " "tűzfal csökkenti az internetről leselkedő biztonsági fenyegetések kockázatát." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Tűzfal" @@ -2192,53 +2185,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "{name} port ({details}) nem érhető el külső hálózaton" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"A Tűzfal démon nem fut. Kérlek futtasd. A Tűzfal alapértelmezetten " -"bekapcsolva érkezik a %(box_name)s eszközödre. Bármely Debian alapú " -"rendszeren (olyan mint %(box_name)s eszközöd) elindíthatod a 'service " -"firewalld start' parancs kiadásával vagy systemd alapú rendszer esetében " -"'systemctl start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Szolgáltatás/port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Engedélyezve" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Letiltva" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Engedélyezett" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Engedélyezett (csak belső)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Engedélyezett (csak külső)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Blokkolva" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2248,13 +2227,13 @@ msgstr "" "tűzfalban is engedélyezve lesz, és ha letiltod a szolgáltatást az a " "tűzfalban szintén le lesz tiltva." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Haladó" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2307,7 +2286,7 @@ msgstr "Beállítás elkezdése" msgid "Setup Complete" msgstr "Beállítás kész" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2326,7 +2305,7 @@ msgstr "" "valamelyikével. Ezek mellett megoszthatod a kódodat az emberekkel szerte a " "világon." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2335,70 +2314,70 @@ msgstr "" "href=\"https://git-scm.com/docs/gittutorial\">Git gyorstalpalót (angolul)." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Olvasási-írási hozzáférés a Git-tárolókhoz" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Egyszerű Git-hoszting" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Érvénytelen tároló URL." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Érvénytelen tárolónév." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "Az új tároló neve vagy URL egy már létező tároló importálásához." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Tároló leírása" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Opcionális, a Gitweben történő megjelenítéshez." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Tároló tulajdonosának a neve" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Privát tároló" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" "Lehetővé teszi, hogy csak az arra jogosult felhasználók férjenek hozzá ehhez " "a tárolóhoz." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Már létezik ilyen nevű tároló." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Tároló neve" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" "Olyan betűkből és számokból álló szöveg ami egyedien azonosítja a tárolót." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Alapértelmezett ág" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "A Gitweb ezt fogja alapértelmezett ágként megjeleníti." @@ -2442,19 +2421,19 @@ msgstr "%(name)s Git-tároló törlése" msgid "Delete this repository permanently?" msgstr "Véglegesen törlöd ezt a tárolót?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Tároló létrehozva." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Hiba történt a tároló létrehozása közben." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Tároló szerkesztve." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Tároló szerkesztése" @@ -2818,7 +2797,7 @@ msgstr "A {box_name} projektről" msgid "{box_name} Manual" msgstr "{box_name} kézikönyv" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2830,7 +2809,7 @@ msgstr "" "biztosít anonimitást, hogy a titkosított adatforgalmat egy világszerte " "önkéntesek által üzemeltetett hálózaton küldi keresztül." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2838,7 +2817,7 @@ msgstr "" "További információk az I2P-ről a projekt weboldalán." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2846,19 +2825,19 @@ msgstr "" "Az első látogatás a megadott webes felületen elindítja a konfigurálási " "folyamatot." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "I2P alkalmazás kezelése" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Anonim hálózat" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P proxy" @@ -2903,7 +2882,7 @@ msgstr "" "le egy peer-to-peer hálózatban. Torrentek hozzáadásával tölthetsz le " "fájlokat, vagy új torrentet hozhatsz létre egy fájl megosztásához." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2913,7 +2892,7 @@ msgstr "" "leírónyelvet támogat, beleértve a Markdown-t és olyan általános bloggolási " "funkciókat, mint például a kommentek és az RSS-hírcsatornák." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2927,15 +2906,15 @@ msgstr "" "meglévőket. A Felhasználók beállítása oldalon " "tudod módosítani ezeket a jogosultságokat vagy hozzáadni új felhasználókat." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki és blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Wiki alkalmazások megtekintése és szerkesztése" @@ -2991,42 +2970,42 @@ msgstr "" "Ez a művelet el fog távolítani minden bejegyzést, oldalt és kommentet " "beleértve a verziótörténetet is. Véglegesen törlöd ezt a wikit vagy blogot?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "{name} wiki létrehozva." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Nem sikerült létrehozni a wikit: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "{name} blog létrehozva." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Nem sikerült létrehozni a blogot: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} törölve." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "{title} nem törölhető: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" "Az infinoted egy szerver a Gobby-hoz, a kollaboratív szövegszerkesztőhöz." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3038,11 +3017,11 @@ msgstr "" "\"Csatlakozás a szerverhez\" lehetőséget (\"Connect to Server\") és írd be a " "{box_name} eszközöd domainnevét." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby-szerver" @@ -3090,7 +3069,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "JavaScript licencinformáció" @@ -3110,7 +3089,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Chat kliens" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3126,7 +3105,7 @@ msgstr "" "úgy éri el, hogy a Let's Encryptnek, egy hitelesítésszolgáltatónak (CA) " "igazolja, hogy ő a domain tulajdonosa." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3139,15 +3118,15 @@ msgstr "" "letsencrypt.org/repository/\">Let's Encrypt aláírási megállapodását " "mielőtt használnád ezt a szolgáltatást." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Tanúsítványok" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Sikertelen tesztelés: Nincsenek konfigurált domainek." @@ -3212,7 +3191,7 @@ msgstr "" "Nincsenek domainek beállítva. Előbb állítsd be a " "domaineket ahhoz, hogy tanúsítványokat kaphass hozzájuk." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3221,34 +3200,34 @@ msgstr "" "A {domain} domain tanúsítványa sikeresen visszavonva. Eltarthat néhány " "pillanatig, mire életbe lép." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "A {domain} domain tanúsítványát nem sikerült visszavonni: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "A {domain} domain sikeresen megkapta a tanúsítványt" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "A {domain} domain nem kapott tanúsítványt: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "{domain} domain tanúsítványa sikeresen törölve" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "{domain} domain tanúsítványát nem sikerült kitörölni: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3265,7 +3244,7 @@ msgstr "" "adott Matrix-szerveren lévő felhasználók föderáción keresztül " "beszélgethetnek az összes többi Matrix-szerver felhasználóival." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3275,7 +3254,7 @@ msgstr "" "videóhívásokhoz. Telepítsd a Coturn " "alkalmazást, vagy konfigurálj egy külső szervert." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3383,7 +3362,7 @@ msgstr "" "szükséged. Kérlek, látogasd meg a Let's " "Encrypt weboldalát ahhoz, hogy beszerezz egyet." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3395,7 +3374,7 @@ msgstr "" "létrehozni. A MediaWiki segítségével wikiszerű weboldalt üzemeltethetsz, " "jegyzeteket készíthetsz, vagy barátaiddal együtt dolgozhatsz projekteken." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3409,7 +3388,7 @@ msgstr "" "létrehozhatsz további felhasználói fiókokat a MediaWiki Special:CreateAccount oldalán." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3417,12 +3396,12 @@ msgstr "" "Bárki elolvashatja, akinek van hozzáférése ehhez a wikihez, viszont csak a " "bejelentkezett felhasználók módosíthatják a tartalmat." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3515,39 +3494,39 @@ msgid "Password update failed. Please choose a stronger password" msgstr "" "Az adattitkosításra használt jelszó. A szerver jelszavával meg kell egyeznie." -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Szabad regisztráció engedélyezve" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Szabad regisztráció letiltva" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Privát mód engedélyezve" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Privát mód letiltva" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Az alapértelmezett felszín megváltozott" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "Domainnév beállítva" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "Domainnév beállítva" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3561,11 +3540,11 @@ msgstr "" "szerverre egy Minetest " "kliensre is szükséged lesz." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Blokk sandbox" @@ -3614,7 +3593,7 @@ msgstr "Ha le van tiltva, a játékosok nem fognak meghalni, ill. megsérülni." msgid "Address" msgstr "Cím" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3805,7 +3784,7 @@ msgstr "Secure Shell (Biztonságos parancsértelmező)" msgid "Services" msgstr "Szolgáltatások" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3814,7 +3793,7 @@ msgstr "" "vagy PPPoE segítségével. Oszd meg ezt a kapcsolatot a hálózaton lévő más " "eszközökkel." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3822,7 +3801,7 @@ msgstr "" "Előfordulhat, hogy más módszerekkel felügyelt eszközök itt nem lesznek a " "konfigurálhatók." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Hálózatok" @@ -4258,7 +4237,7 @@ msgstr "Kapcsolat szerkesztése" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Szerkesztés" @@ -4363,7 +4342,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Módszer" @@ -4379,7 +4358,7 @@ msgstr "DNS-szerver" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Alapértelmezett" @@ -4392,7 +4371,7 @@ msgid "This connection is not active." msgstr "Ez a kapcsolat nem aktív." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Biztonság" @@ -4981,7 +4960,7 @@ msgstr "Kapcsolat törölve: {name}." msgid "Failed to delete connection: Connection not found." msgstr "A kapcsolat törlése sikertelen, mivel nem található." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4999,20 +4978,20 @@ msgstr "" "eszközödön keresztül elérheted az internetet is további biztonság és " "anonimitás érdekében." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Csatlakozás a VPN-szolgáltatásokhoz" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Virtuális magánhálózat" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5023,58 +5002,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Átállás ECC-re" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Az OpenVPN telepítése jelenleg RSA-t használ. A modern Elliptikus Görbe " -"Kriptográfiára való váltás javítja a kapcsolat létrehozásának sebességét és " -"a biztonságot. Ez a művelet visszafordíthatatlan. A legtöbb egylapos " -"számítógépen mindössze néhány percet vesz igénybe." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Az OpenVPN minden új telepítése a %(box_name)s eszközön alapértelmezés " -"szerint ECC-t fog használni. Javasoljuk a mielőbbi áttérést." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Figyelmeztetés: A meglévő kliensprofilokat ez a művelet " -"hatálytalanítja. Minden %(box_name)son lévő OpenVPN-felhasználónak le kell " -"töltenie az új profilját. A szerverhez való csatlakozáshoz az ECC-vel " -"kompatibilis OpenVPN-klienseket kell használni." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Költöztetés" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Ahhoz, hogy a %(box_name)s eszközöd virtuális magánhálózatára (VPN) " @@ -5083,18 +5025,19 @@ msgstr "" "platformra elérhetők. Kattints a fentebbi „További információk…” gombra az " "ajánlott kliensek és a beállítási utasítások megtekintéséhez." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "A profil a %(box_name)s eszköz minden egyes felhasználójára egyedi. Tartsd " "titokban." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Saját profilom letöltése" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5108,19 +5051,19 @@ msgstr "" "szolgáltatásai nem érhetők el az internet felől. Ez magában foglalja az " "alábbi eseteket:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "A {box_name} eszközöd egy korlátozott tűzfal mögött van." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "A {box_name} eszközöd egy olyan (vezeték nélküli) routerhez kapcsolódik, " "amelyet te nem állíthatsz be." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5128,7 +5071,7 @@ msgstr "" "Az internetszolgáltatód nem biztosít neked külső IP-címet, ehelyett hálózati " "címfordításon (NAT) keresztül tudod elérni az internetet." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5136,11 +5079,11 @@ msgstr "" "Az internetszolgáltatód nem biztosít neked statikus IP-címet és az IP-címed " "mindig megváltozik, amikor az internetre csatlakozol." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Az internetszolgáltatód korlátozza a bejövő kapcsolatokat." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5154,23 +5097,23 @@ msgstr "" "net. A jövőben talán a barátod {box_name} eszközét is lehetőséged lesz " "használni erre a célra." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Nyilvános láthatóság" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite domain" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Szerver domain" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5178,31 +5121,31 @@ msgstr "" "Válaszd ki a pagekite szerveredet. Állítsd „pagekite.net” -re, ha az " "alapértelmezett pagekite.net szervert szeretnéd használni." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Szerver port" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "A pagekite szervered portja (alapértelmezett: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite név" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Például: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Érvénytelen kite név" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite titkos kulcs" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5210,35 +5153,35 @@ msgstr "" "A kite-hoz kapcsolódó titkos kulcs vagy a fiókod alapértelmezett titkos " "kulcsa, ha nem lett titkos kulcs beállítva a kite-ra." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protokoll" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "külső (frontend) port" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "belső (freedombox) port" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Aldomainek engedélyezése" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Törölt egyéni szolgáltatás" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Ez a szolgáltatás már elérhető szabványosként." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Egyedi szolgáltatás hozzáadva" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Ez a szolgáltatás már létezik" @@ -5276,29 +5219,29 @@ msgstr "" "HTTPS a 443-as porttól eltérő portokon történő használata közismerten " "problémákat okoz." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Webszerver (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Az oldal itt lesz elérhető: http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Webszerver (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Az oldal itt lesz elérhető: https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Biztonságos parancsértelmező (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5350,8 +5293,8 @@ msgstr "" "Jelenleg telepítés vagy frissítés zajlik. Érdemes megvárni a folyamat végét " "a leállítás vagy újraindítás előtt." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Újraindítás" @@ -5401,6 +5344,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Leállítás most" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5448,7 +5424,7 @@ msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" "Hozzáférés a {url} URL-hez {proxy} proxy használatával tcp{kind}-on keresztül" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5465,7 +5441,7 @@ msgstr "" "szolgáltatását, aminek segítségével mindig online lehetsz és egy, vagy több " "Quassel klienssel kapcsolódhatsz hozzá a mobilodról vagy az asztali gépedről." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your asztali és mobil " "eszközökhöz is." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC-kliens" @@ -5489,7 +5465,7 @@ msgstr "IRC-kliens" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5505,7 +5481,7 @@ msgstr "" "alkalmazásra is. A Radicale elérhető bármely felhasználó számára a " "{box_name} eszközön." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5515,12 +5491,12 @@ msgstr "" "címjegyzékek létrehozását támogatja. Nem támogatja az események vagy " "kapcsolatok hozzáadását, ezeket külön kliens segítségével kell elvégezni." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Naptár és címjegyzék" @@ -5593,7 +5569,7 @@ msgstr "" "és a felhasználónevet. A keresés gombra kattintva ki lesz listázva az összes " "elérhető naptár és címjegyzék." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Hozzáférési jogok beállításai frissítve" @@ -5685,7 +5661,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Hírcsatornák olvasása és feliratkozás" @@ -5698,7 +5674,7 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5706,7 +5682,7 @@ msgstr "" "A Samba lehetővé teszi a fájlok és mappák megosztását a FreedomBox és a " "helyi hálózat más számítógépei között." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5719,11 +5695,11 @@ msgstr "" "\\{hostname} (Windows alatt) vagy az smb://{hostname}.local (Linux és Mac " "alatt) címen érhetők el. Háromféle megosztás közül választhatsz: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Nyílt megosztás - a helyi hálózaton belül mindenki számára elérhető." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5731,7 +5707,7 @@ msgstr "" "Csoportos megosztás - csak a freedombox-share csoportba tartozó FreedomBox " "felhasználók számára elérhető." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5739,15 +5715,15 @@ msgstr "" "Otthoni megosztás - a freedombox-share csoport minden felhasználójának saját " "privát tárhelye lehet." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Hozzáférés a privát megosztásokhoz" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Hálózati tárhely" @@ -5836,15 +5812,15 @@ msgstr "Megosztás neve" msgid "Action" msgstr "Művelet" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS lemez" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Nyílt megosztás" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Csoport megosztás" @@ -5870,7 +5846,7 @@ msgstr "Megosztás letiltva." msgid "Error disabling share: {error_message}" msgstr "Hiba történt a megosztás letiltásakor: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5878,7 +5854,7 @@ msgstr "" "A Searx egy magánszférát tiszteletben tartó internetes metakereső. Több " "keresőmotor eredményeit gyűjti össze és jeleníti meg." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5886,41 +5862,41 @@ msgstr "" "A Searx segítségével elkerülhető, hogy a keresőmotorok nyomon kövessék és " "profilozzák a felhasználót. Sütiket eleve nem tárol." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Keresés a weben" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Webes keresés" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Biztonságos keresés" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Válaszd ki a felnőtt tartalmak alapértelmezett szűrési fokozatát, ez a " "keresési eredményeken lesz alkalmazva." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Enyhe" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Szigorú" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Nyilvános hozzáférés engedélyezése" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Engedélyezi ennek az alkalmazásnak a használatát bárkinek, aki el tudja érni." @@ -6104,7 +6080,7 @@ msgstr "Könyvjelzők" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6114,7 +6090,7 @@ msgstr "" "internetes forgalmad védelmére terveztek. Felhasználható az internetes " "szűrők és cenzúra megkerülésére." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6127,7 +6103,7 @@ msgstr "" "Helyi eszközeiddel csatlakozhatsz erre a proxy-ra, és az adataik titkosítva " "és proxizva lesznek a Shadowsocks-szerveren keresztül." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6136,41 +6112,41 @@ msgstr "" "címét a készülékeden, böngésződben vagy alkalmazásodban a http://" "freedombox_eszkozod_cime:1080/ címre" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Socks5 Proxy" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Ajánlott" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Szerver" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "A szerver állomásneve vagy IP-címe" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "A szerver portja" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Az adattitkosításra használt jelszó. A szerver jelszavával meg kell egyeznie." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Titkosítási módszer. A szerver beállításával meg kell egyeznie." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6179,15 +6155,15 @@ msgstr "" "Megosztás lehetővé teszi számodra hogy fájlokat és mappákat ossz meg a weben " "keresztül felhasználók kiválasztott csoportjaival a {box_name} eszközödön." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Megosztás" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Megosztás neve" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6195,31 +6171,31 @@ msgstr "" "Kisbetűkből és számokból álló szöveg ami egyedien azonosítja a megosztást. " "Például: media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "A megosztás elérési útja" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" "Helyi elérési út a szerveren egy mappára, amelyet meg szeretnél osztani." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Nyilvános megosztás" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" "A mappában lévő fájlok elérhetővé tétele a linkkel rendelkező személyek " "számára." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" "Azok a felhasználói csoportok akik olvashatják a fájlokat a megosztásban:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6227,11 +6203,11 @@ msgstr "" "A kiválasztott felhasználói csoportok felhasználói képesek lesznek a " "megosztásban lévő fájlokat olvasni." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Egy megosztás ezzel a névvel már létezik." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" "A megosztásnak nyilvánosnak vagy legalább egy csoporttal megosztottnak kell " @@ -6270,19 +6246,19 @@ msgstr "Megosztás hozzáadva." msgid "Add Share" msgstr "Megosztás hozzáadása" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Megosztás szerkesztve." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Megosztás szerkesztése" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Megosztás törölve." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6292,7 +6268,7 @@ msgstr "" "létrehozását és kezelését. Ez akkor hasznos, ha a rendszert egy korábbi, jól " "működő állapotába szeretnéd visszaállítani egy nem kívánt változtatás után." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6304,7 +6280,7 @@ msgstr "" "pillanatképek automatikusan ki lesznek takarítva az alábbi beállítások " "szerint." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for Biztonsági mentéseket, mivel a pillanatképek csak " "ugyanazon a partíción tárolhatók, mint amelyen készülnek. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Tárhelypillanatképek" @@ -6418,7 +6394,7 @@ msgstr "Dátum" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Pillanatképek törlése" @@ -6472,59 +6448,59 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Visszaállítás erre a pillanatképre: %(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "kézzel létrehozva" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "idővonal" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Pillanatképek kezelése" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Pillanatkép létrehozva." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Tárhelypillanatképek konfigurációja frissítve" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Hiba a művelet közben: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Kiválasztott pillanatképek törölve" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" "A Tárhelypillanatképek funkció jelenleg is használatban van. Kérlek, próbáld " "újra később." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "A {number} számú pillanatképre visszaállítva." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "A visszaállítás befejezéséhez a rendszert újra kell indítani." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Visszaállítás pillanatképre" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6536,7 +6512,7 @@ msgstr "" "számítógép felügyeleti feladatokat hajthat végre, fájlokat másolhat vagy " "egyéb szolgáltatásokat futtathat ilyen kapcsolat használatával." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "SSH-szerver" @@ -6574,14 +6550,6 @@ msgstr "Algoritmus" msgid "Fingerprint" msgstr "Ujjlenyomat" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "A jelszavas SSH-hitelesítés le van tiltva." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "Jelszavas SSH-hitelesítés engedélyezve." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Egyszeri bejelentkezés" @@ -6594,7 +6562,7 @@ msgstr "Bejelentkezés" msgid "Logged out successfully." msgstr "Sikeres kijelentkezés." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6606,108 +6574,108 @@ msgstr "" "fel- és lecsatolhatsz cserélhető adathordozókat, kibővítheted a root " "partíciót, stb." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Tárhely" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} byte" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "A művelet sikertelen." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "A művelet meg lett szakítva." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Az eszköz leválasztása már folyamatban van." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" "A művelet nem támogatott a hiányzó illesztőprogram/eszköz támogatása miatt." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "A művelet túllépte az időkorlátot." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" "A művelet fel fogja ébreszteni a lemezt, amely mély-alvó állapotban van." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Foglalt eszköz leválasztásának a kísérlete." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "A művelet már meg lett szakítva." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Nem vagy jogosult végrehajtani a kért műveletet." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Az eszköz már fel lett csatolva." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Az eszköz nincs felcsatolva." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Nem használhatod a kért lehetőséget." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Az eszközt egy másik felhasználó felcsatolva." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Kevés a szabad hely a rendszerpartíción: {percent_used}% felhasználva, " "{free_space} szabad." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Kevés tárhely" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Lemezhiba várható" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6716,39 +6684,39 @@ msgstr "" "A {id} lemez azt jelzi, hogy a közeljövőben valószínűleg meghibásodik. " "Másold át az adatokat, amíg még lehet, és cseréld ki a meghajtót." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Érvénytelen könyvtárnév." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "A könyvtár nem létezik." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Az elérési út nem könyvtár." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "A könyvtár nem olvasható a felhasználó által." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "A felhasználónak nincs írási jogosultsága a könyvtár felett." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Könyvtár" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Alkönyvtár (opcionális)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Megosztás" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Egyéb könyvtár (add meg alább)" @@ -6785,7 +6753,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Root partíció kibővítése" @@ -6808,30 +6776,30 @@ msgstr "" "%(expandable_root_size)s további szabad tárterület lesz elérhető a root " "partíción." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Hiba a partíció kibővítése során: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "A partíció kibővítése sikerült." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} biztonságosan kivehető." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Az eszköz biztonságosan kivehető." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Hiba történt az eszköz kiadása során: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6843,7 +6811,7 @@ msgstr "" "fájljain végzett módosítások a többi eszközön is automatikusan jelentkeznek, " "amennyiben telepítve van a szolgáltatás." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6863,20 +6831,20 @@ msgstr "" "felület csak az \"admin\" vagy a \"syncthing-access\" csoporthoz tartozó " "felhasználók számára hozzáférhető." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "A Syncthing alkalmazás beállítása" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Fájlszinkronizáció" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6890,7 +6858,7 @@ msgstr "" "torproject.org/download/download-easy.html.en\">Tor böngésző használatát " "javasolja." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, fuzzy, python-brace-format #| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." msgid "" @@ -6899,40 +6867,40 @@ msgid "" msgstr "" "Egy Tor SOCKS port elérhető a %(box_name)s eszközöd 9050-es TCP-portján." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor Onion szolgáltatás" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor Socks proxy" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor híd relay" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor relay port elérhető" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 átvitel regisztrálva" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 átvitel regisztrálva" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Hozzáférés a {url} URL-hez tcp{kind}-on Tor használatával" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Hagyd jóvá a Tor használatát {url} célcímhez tcp{kind} protokollon" @@ -7053,13 +7021,13 @@ msgstr "Onion-szolgáltatás" msgid "Ports" msgstr "Portok" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Hiba történt a beállítás közben." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -7120,7 +7088,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7130,7 +7098,7 @@ msgstr "" "tervezve, hogy elérhetővé tegye a hírolvasást bárhonnan, miközben igyekszik " "egy valódi asztali alkalmazás érzetét kelteni." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Tiny Tiny RSS can be accessed by any felhasználó elérheti, aki {box_name} bejelentkezéssel " "rendelkezik." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7152,11 +7120,11 @@ msgstr "" "hez, használd a /tt-rss-app URL-t a " "csatlakozáshoz." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Hírcsatorna-olvasó" @@ -7164,13 +7132,13 @@ msgstr "Hírcsatorna-olvasó" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "A legfrissebb szoftver- és biztonsági frissítések ellenőrzése és alkalmazása." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7183,22 +7151,22 @@ msgstr "" "újraindítása szükségesnek bizonyul, akkor a rendszer automatikusan 02:00-kor " "újraindul, ami miatt az összes alkalmazás rövid ideig nem lesz elérhető." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Szoftverfrissítések" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox frissítve" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "A disztribúció frissítése nem tudott elindulni" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7209,11 +7177,11 @@ msgstr "" "disztribúció frissítését a rendszer 24 óra múlva újrapróbálja, ha " "engedélyezve van." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "A disztribúció frissítése elindult" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7392,46 +7360,46 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Disztribúció frissítés engedélyezve" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Hiba a nem felügyelt frissítések konfigurálása közben: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Automatikus frissítések engedélyezve" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Automatikus frissítések kikapcsolva" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Disztribúció frissítés engedélyezve" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Disztribúció frissítés letiltva" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "A frissítési folyamat elkezdődött." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "A frissítést nem sikerült elindítani." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Gyakori funkciófrissítések aktiválva." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Distribution upgrade enabled" msgid "Starting distribution upgrade test." msgstr "Disztribúció frissítés engedélyezve" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7442,7 +7410,7 @@ msgstr "" "alkalmazások megkövetelik továbbá, hogy a felhasználói fiók egy csoport " "tagja legyen, hogy a felhasználó hozzáférhessen az alkalmazáshoz." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7454,15 +7422,15 @@ msgstr "" "az admin csoport felhasználói módosíthatják az alkalmazásokat vagy " "a rendszerbeállításokat." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Felhasználók és csoportok" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Hozzáférés az összes szolgáltatáshoz és rendszerbeállításhoz" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP-bejegyzés ellenőrzése: \"{search_item}\"" @@ -7481,22 +7449,22 @@ msgid "" msgstr "" "Szükséges. Legfeljebb 150 karakter. Csak angol betűk, számjegyek és @/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Hitelesítési jelszó" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" "A fiókmódosítások engedélyezéséhez add meg \"{user}\" felhasználó jelszavát." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Érvénytelen jelszó." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7512,12 +7480,12 @@ msgstr "" "képesek bejelentkezni a rendszerbe, ahol adminisztrátori jogosultságokkal " "rendelkeznek (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "LDAP-felhasználó létrehozása sikertelen: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -7537,43 +7505,43 @@ msgstr "" "jelszó nélkül jelentkezzen be. Több kulcs is megadható; soronként egy. Az " "üres, illetve # jellel kezdődő sorok nem számítanak." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "LDAP-felhasználó átnevezése sikertelen." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Nem sikerült eltávolítani a felhasználót a csoportból." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Nem sikerült hozzáadni a felhasználót a csoporthoz." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "SSH-kulcsok beállítása sikertelen." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Nem sikerült a felhasználói állapot megváltoztatása." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "LDAP-felhasználó jelszavának megváltoztatása sikertelen." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Nem sikerült hozzáadni az új felhasználót a rendszergazdai csoporthoz: " "{error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Nem sikerült a konzolos hozzáférés korlátozása: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Felhasználói fiók létrehozva, bejelentkezés sikeres" @@ -7590,12 +7558,12 @@ msgstr "Jelszó mentése" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Felhasználó létrehozása" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Felhasználó törlése" @@ -7637,13 +7605,19 @@ msgid "The following administrator accounts exist in the system." msgstr "Az alábbi rendszergazdai fiókok léteznek a rendszerben." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Töröld ezeket a fiókokat a parancssorból, és frissítsd az oldalt, hogy " "létrehozz egy olyan fiókot, amely használható a %(box_name)s eszközöddel. A " @@ -7652,7 +7626,7 @@ msgstr "" "%(box_name)s eszközödön, akkor hagyd ki ezt a lépést." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Felhasználók" @@ -7685,34 +7659,34 @@ msgstr "" msgid "Save Changes" msgstr "Változtatások mentése" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "%(username)s nevű felhasználó létrehozva." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "%(username)s nevű felhasználó frissítve." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Felhasználó szerkesztése" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "{user} nevű felhasználó törölve." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "LDAP-felhasználó törlése sikertelen." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Jelszómódosítás" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "A jelszó módosítása sikeres." @@ -8049,7 +8023,7 @@ msgstr "Szerverrel létesített kapcsolat törlése" msgid "Server deleted." msgstr "Szerver törölve." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8063,7 +8037,7 @@ msgstr "" "témák segítségével választható. Az adminisztrációs felület és az előállított " "weboldalak alkalmasak a mobileszközök számára." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8077,7 +8051,7 @@ msgstr "" "futtatni. Engedélyezd a permalinkeket a rendszergazdai felületen az oldalak " "és bejegyzések jobb URL-jeihez." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8088,7 +8062,7 @@ msgstr "" "elérése érdekében mentsd el a könyvjelzőid közé az admin lapot." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8098,12 +8072,12 @@ msgstr "" "frissítését a rendszergazdai felületről. További bővítmények vagy témák " "telepítése és frissítése saját felelősségre történhet." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Weboldal és blog" @@ -8120,7 +8094,7 @@ msgstr "" "teszi lehetővé a WordPress webhely vagy blog megtekintését. Csak a WordPress " "kezdeti beállításának elvégzése után engedélyezd." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8142,7 +8116,7 @@ msgstr "" "tartózkodási hely alapján. Az egyes fényképek közvetlen link elküldésével " "megoszthatók másokkal." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8154,11 +8128,11 @@ msgstr "" "rendszerben is létre kell hozni egy-egy fiókot ugyanazzal a " "felhasználónévvel." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Fotó szervező" @@ -8213,116 +8187,110 @@ msgstr "" msgid "Finished: {name}" msgstr "Szolgáltatás letiltva: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "A(z) {package_name} a legfrissebb verzió ({latest_version})" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "Hiba történt a biztonsági mentés közben" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "telepítés" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "letöltés" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "adathordozó csere" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "konfigurációs fájl: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Alkalmazások telepítése" -#: plinth/setup.py:42 +#: plinth/setup.py:43 #, fuzzy #| msgid "Updating..." msgid "Updating app" msgstr "Frissítés…" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Alkalmazás telepítve." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Legutolsó frissítés" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Alkalmazások telepítése" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Alkalmazás telepítve." -#: plinth/setup.py:451 +#: plinth/setup.py:452 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8383,53 +8351,54 @@ msgstr "Telepítés" msgid "Service %(service_name)s is not running." msgstr "A szolgáltatás nem fut (%(service_name)s)." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Alapvető funkcionalitás és webes felület a %(box_name)s számára" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Kezdőlap" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Kezdőlap" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Alkalmazások" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Alkalmazások" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Rendszer" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Rendszer" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Jelszómódosítás" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Leállítás" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Kijelentkezés" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Válassz nyelvet" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Bejelentkezés" @@ -8722,6 +8691,77 @@ msgstr "" msgid "Gujarati" msgstr "Gudzsaráti" +#~ msgid "Enable DNSSEC" +#~ msgstr "DNSSEC engedélyezése" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Domainnévrendszer biztonsági kiterjesztéseinek engedélyezése" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "A Tűzfal démon nem fut. Kérlek futtasd. A Tűzfal alapértelmezetten " +#~ "bekapcsolva érkezik a %(box_name)s eszközödre. Bármely Debian alapú " +#~ "rendszeren (olyan mint %(box_name)s eszközöd) elindíthatod a 'service " +#~ "firewalld start' parancs kiadásával vagy systemd alapú rendszer esetében " +#~ "'systemctl start firewalld'." + +#~ msgid "Migrate to ECC" +#~ msgstr "Átállás ECC-re" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Az OpenVPN telepítése jelenleg RSA-t használ. A modern Elliptikus Görbe " +#~ "Kriptográfiára való váltás javítja a kapcsolat létrehozásának sebességét " +#~ "és a biztonságot. Ez a művelet visszafordíthatatlan. A legtöbb egylapos " +#~ "számítógépen mindössze néhány percet vesz igénybe." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Az OpenVPN minden új telepítése a %(box_name)s eszközön alapértelmezés " +#~ "szerint ECC-t fog használni. Javasoljuk a mielőbbi áttérést." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Figyelmeztetés: A meglévő kliensprofilokat ez a művelet " +#~ "hatálytalanítja. Minden %(box_name)son lévő OpenVPN-felhasználónak le " +#~ "kell töltenie az új profilját. A szerverhez való csatlakozáshoz az ECC-" +#~ "vel kompatibilis OpenVPN-klienseket kell használni." + +#~ msgid "Migrate" +#~ msgstr "Költöztetés" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "A jelszavas SSH-hitelesítés le van tiltva." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Jelszavas SSH-hitelesítés engedélyezve." + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "Hiba történt a biztonsági mentés közben" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Alapvető funkcionalitás és webes felület a %(box_name)s számára" + #~ msgid "Network Connections" #~ msgstr "Hálózati kapcsolatok" diff --git a/plinth/locale/id/LC_MESSAGES/django.po b/plinth/locale/id/LC_MESSAGES/django.po index 9b5144214..c940700b9 100644 --- a/plinth/locale/id/LC_MESSAGES/django.po +++ b/plinth/locale/id/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Indonesian (FreedomBox)\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Indonesian calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1038,29 +1031,29 @@ msgstr "" "mengakses aplikasi. Semua pengguna dengan akses dapat menggunakan semua " "perpustakaan." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Gunakan perpustakaan e-book Calibre" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "kaliber" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Perpustakaan e-book" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Nama perpustakaan baru" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Perpustakaan dengan nama ini sudah ada." @@ -1108,20 +1101,20 @@ msgstr "Pergi ke perpustakaan %(library)s" msgid "Delete library %(library)s" msgstr "Hapus perpustakaan %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Perpustakaan yang dibuat." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Terjadi kesalahan saat membuat perpustakaan." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} dihapus." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Tidak dapat menghapus {name}: {error}" @@ -1169,7 +1162,7 @@ msgstr "Kokpit" msgid "Server Administration" msgstr "Administrasi Server" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1177,18 +1170,18 @@ msgstr "" "Di sini Anda dapat mengatur beberapa opsi konfigurasi umum seperti nama " "host, nama domain, halaman beranda server web dll." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Konfigurasi Umum" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Konfigurasi" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1304,47 +1297,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Kesalahan pengaturan hostname: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Hostname set" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Kesalahan pengaturan nama domain: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Set nama domain" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Kesalahan pengaturan Webserver Halaman Beranda: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Set Halaman Rumah WebServer" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Kesalahan mengubah mode lanjutan: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Menampilkan aplikasi dan fitur canggih" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Menyembunyikan aplikasi dan fitur canggih" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1356,7 +1349,7 @@ msgstr "" "dan server komunikasi lainnya dapat menggunakannya untuk menetapkan " "panggilan antar pihak yang tidak dapat terhubung satu sama lain." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ejabberd memerlukan dikonfigurasi dengan rincian yang " "disediakan disini." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "Helper VoIP" @@ -1429,11 +1422,11 @@ msgstr "Kesalahan pengaturan zona waktu: {exception}" msgid "Time zone set" msgstr "Set zona waktu" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge adalah klien BitTorrent yang menampilkan UI Web." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1441,16 +1434,16 @@ msgstr "" "Kata sandi default adalah 'Deluge', tetapi Anda harus masuk dan mengubahnya " "segera setelah mengaktifkan layanan ini." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Unduh file menggunakan aplikasi BitTorrent" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Membanjiri" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Klien Web BitTorrent" @@ -1578,7 +1571,7 @@ msgstr "Hasil" msgid "Diagnostic Test" msgstr "Tes Diagnostik" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1590,7 +1583,7 @@ msgstr "" "internet. Ini akan mencegah orang lain menemukan layanan yang disediakan " "oleh {box_name} ini." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1608,7 +1601,7 @@ msgstr "" "jika seseorang dari Internet meminta nama DNS Anda, mereka akan mendapatkan " "Tanggapan dengan alamat IP Anda saat ini." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 #, fuzzy #| msgid "" #| "If you are looking for a free dynamic DNS account, you may find a free " @@ -1628,11 +1621,11 @@ msgstr "" "URL pembaruan gratis di freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Klien DNS Dinamis" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Nama Domain Dinamis" @@ -1769,7 +1762,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1838,7 +1831,7 @@ msgstr "Hapus koneksi" msgid "Already up-to-date" msgstr "Automatic" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1846,7 +1839,7 @@ msgstr "" "XMPP adalah protokol komunikasi terbuka dan standar. Di sini Anda dapat " "menjalankan dan mengkonfigurasi server XMPP Anda, yang disebut Ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientKlien XMPP. Saat diaktifkan, ejabberd dapat diakses " "oleh pengguna dengan sebuah {box_name} login." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn atau konfigurasikan server " "eksternal." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "Ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Server obrolan" @@ -1992,14 +1985,14 @@ msgstr "" "terlihat seperti nama pengguna @%(domainname)s. Anda dapat mengatur " "domain Anda pada sistem Konfigurasi halaman." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2007,7 +2000,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2017,13 +2010,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2166,7 +2159,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2177,7 +2170,7 @@ msgstr "" "masuk dan keluar pada {box_name} Anda. Menjaga firewall diaktifkan dan " "dikonfigurasi dengan benar mengurangi risiko ancaman keamanan dari Internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall" @@ -2197,53 +2190,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port {name} ({details}) tidak tersedia untuk jaringan eksternal" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Daemon firewall tidak berjalan. Silakan jalankan. Firewall datang diaktifkan " -"secara default pada %(box_name)s. Pada sistem berbasis debian apa pun " -"(seperti %(box_name)s) Anda dapat menjalankannya menggunakan perintah " -"'Service firewalld start' atau Dalam hal sistem dengan systemd 'systemctl " -"mulai firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Layanan/Port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Aktifkan" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Non-Aktifkan" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Diizinkan" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Diizinkan (hanya internal)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Diizinkan (hanya eksternal)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Diblokir" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2253,13 +2232,13 @@ msgstr "" "diizinkan di firewall dan ketika Anda menonaktifkan layanan, itu juga " "dinonaktifkan di firewall." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Maju" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2312,7 +2291,7 @@ msgstr "Jalankan Pengaturan" msgid "Setup Complete" msgstr "Pengaturan Selesai" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2330,7 +2309,7 @@ msgstr "" "beberapa klien grafis yang tersedia. Dan Anda dapat membagikan kode Anda " "dengan orang-orang di seluruh dunia." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2338,67 +2317,67 @@ msgstr "" "Untuk mempelajari lebih lanjut tentang cara menggunakan git kunjungi tutorial git ." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Akses baca-tulis ke repositori git" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Hosting Git Sederhana" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "URL repositori tidak valid." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Nama repositori tidak valid." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "Nama repositori atau URL baru untuk mengimpor repositori yang ada." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Deskripsi repositori" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Opsional, untuk ditampilkan di Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Nama pemilik repositori" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Penyimpanan Pribadi" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Berikan hanya pengguna yang berwenang untuk mengakses repositori ini." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Sebuah repositori dengan nama ini sudah ada." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Nama repositori" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "String alfa-numerik yang secara unik mengidentifikasi repositori." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Cabang default" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb menampilkan ini sebagai cabang default." @@ -2442,19 +2421,19 @@ msgstr "Hapus git repositori %(name)s " msgid "Delete this repository permanently?" msgstr "Hapus repositori ini secara permanen?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Repositori dibuat." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Terjadi kesalahan saat membuat repositori." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Diedit repositori." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Edit Repositori" @@ -2813,7 +2792,7 @@ msgstr "Tentang {box_name}" msgid "{box_name} Manual" msgstr "Panduan {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2825,7 +2804,7 @@ msgstr "" "memberikan anonimitas dengan mengirimkan lalu lintas terenkripsi melalui " "jaringan yang dikelola sukarela yang didistribusikan di seluruh dunia." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2833,7 +2812,7 @@ msgstr "" "Temukan informasi lebih lanjut tentang i2p pada proyek mereka, Halaman Beranda." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2841,19 +2820,19 @@ msgstr "" "Kunjungan pertama ke antarmuka web yang disediakan akan memulai proses " "konfigurasi." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Kelola aplikasi I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2p" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Jaringan Anonimitas" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2p proxy" @@ -2903,7 +2882,7 @@ msgstr "" "to-peer. Unduh file dengan menambahkan torrents atau buat torrent baru untuk " "berbagi file." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2913,7 +2892,7 @@ msgstr "" "bahasa markup ringan, termasuk Markdown, dan fungsionalitas blogging umum " "seperti komentar dan umpan RSS." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2927,15 +2906,15 @@ msgstr "" "\"{users_url}\">Konfigurasi Pengguna, Anda dapat mengubah izin ini atau " "menambahkan pengguna baru." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "Ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki dan Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Lihat dan edit aplikasi Wiki" @@ -2991,41 +2970,41 @@ msgstr "" "Tindakan ini akan menghapus semua posting, halaman, dan komentar termasuk " "riwayat revisi. Hapus wiki atau blog ini secara permanen?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Membuat wiki {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Tidak dapat membuat wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "membuat blog {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Tidak dapat membuat blog: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} dihapus." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Tidak dapat menghapus {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "Infinoted adalah server untuk gobby, editor teks kolaboratif." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3036,11 +3015,11 @@ msgstr "" "a>, desktop client dan instal. Kemudian mulai gobby dan pilih \"Hubungkan ke " "Server\" dan masukkan nama domain {box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "Menginfisi" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Server Gobby" @@ -3088,7 +3067,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Informasi Lisensi JavaScript" @@ -3108,7 +3087,7 @@ msgstr "Jsxc" msgid "Chat Client" msgstr "Obrolan Klien" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3124,7 +3103,7 @@ msgstr "" "pengguna adalah pemilik sebuah domain ke Let's Encrypt, sebuah otoritas " "sertifikat (CA)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3137,15 +3116,15 @@ msgstr "" "repository/\">Perjanjian Pelanggan Let's Encrypt sebelum menggunakan " "layanan ini." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Sertifikat" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Tidak dapat menguji: Tidak ada domain yang dikonfigurasi." @@ -3210,7 +3189,7 @@ msgstr "" "Tidak ada domain yang dikonfigurasi. " "mengkonfigurasi domain untuk dapat memperoleh sertifikat untuk mereka." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3219,34 +3198,34 @@ msgstr "" "Sertifikat berhasil dicabut untuk domain {domain}. Ini mungkin memakan waktu " "beberapa saat untuk mulai berlaku." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Gagal mencabut sertifikat untuk domain {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Sertifikat berhasil diperoleh untuk domain {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Gagal memperoleh sertifikat untuk domain {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Sertifikat berhasil dihapus untuk domain {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Gagal menghapus sertifikat untuk domain {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3263,7 +3242,7 @@ msgstr "" "Pengguna pada server matriks tertentu dapat berkomunikasi dengan pengguna di " "semua server matriks lainnya melalui Federation." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3273,7 +3252,7 @@ msgstr "" "Pasang aplikasi Coturn atau konfigurasikan " "server eksternal." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Sinaps Matrix" @@ -3360,7 +3339,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3368,7 +3347,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3377,18 +3356,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3463,39 +3442,39 @@ msgstr "" "Kata sandi yang digunakan untuk mengenkripsi data. Harus mencocokkan kata " "sandi server." -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Pendaftaran publik diaktifkan" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Pendaftaran publik dinonaktifkan" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Mode privat diaktifkan" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Mode privat dinonaktifkan" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "Set nama domain" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "Set nama domain" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3504,11 +3483,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3553,7 +3532,7 @@ msgstr "" msgid "Address" msgstr "Address" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3714,19 +3693,19 @@ msgstr "Secure Shell" msgid "Services" msgstr "Layanan" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Jaringan" @@ -4072,7 +4051,7 @@ msgstr "Sunting Koneksi" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Sunting" @@ -4177,7 +4156,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -4193,7 +4172,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -4206,7 +4185,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4742,7 +4721,7 @@ msgstr "Koneksi {name} dihapus." msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4753,20 +4732,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Sambungkan ke layanan VPN" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Jaringan Privat Virtual" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4776,61 +4755,29 @@ msgstr "Unduh Profil" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Migrasi ke ECC" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Migrasi" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Unduh profil saya" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4839,33 +4786,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "ISP Anda membatasi koneksi masuk." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4874,87 +4821,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Visibilitas Publik" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "Domain PageKite" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Domain peladen" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Port Peladen" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "nama Kite" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Contoh: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protokol" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Aktifkan Subdomain" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "layanan kustom yang dihapus" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4990,29 +4937,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Server Web (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Situs akan tersedia di http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Web Server (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5056,8 +5003,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Mulai ulang" @@ -5099,6 +5046,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Matikan Sekarang" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5130,7 +5110,7 @@ msgstr "Proksi Web" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Akses {url} dengan proksi {proxy} pada tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5141,7 +5121,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "Klien IRC" @@ -5161,7 +5141,7 @@ msgstr "Klien IRC" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5171,19 +5151,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5242,7 +5222,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -5314,7 +5294,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5327,13 +5307,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5342,31 +5322,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Penyimpanan Berkas Jaringan" @@ -5448,19 +5428,19 @@ msgstr "Shared" msgid "Action" msgstr "Aksi" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 #, fuzzy #| msgid "Add Service" msgid "Open Share" msgstr "Tambah Layanan" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 #, fuzzy #| msgid "Add Service" msgid "Group Share" @@ -5490,51 +5470,51 @@ msgstr "Bagikan dinonaktifkan." msgid "Error disabling share: {error_message}" msgstr "Kesalahan pemasangan aplikasi: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Jelajahi web" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Pencarian Web" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Pencarian Aman" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Moderat" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Ketat" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5691,14 +5671,14 @@ msgstr "Bookmark" msgid "Shaarlier" msgstr "Shaarli" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5707,99 +5687,99 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Proksi Socks5" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Disarankan" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Peladen" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Alamat IP atau hostname Peladen" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Nomor port peladen" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Kata sandi yang digunakan untuk mengenkripsi data. Harus mencocokkan kata " "sandi server." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Metode enkripsi. Harus mencocokkan setelan pada peladen." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Berbagi" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Nama pembagian" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Jalur untuk berbagi" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Bagikan publik" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5836,26 +5816,26 @@ msgstr "Bagikan ditambahkan." msgid "Add Share" msgstr "Tambah Bagikan" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Bagikan diedit." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Sunting Bagikan" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Bagikan dihapus." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5863,14 +5843,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Penyimpanan Snapshot" @@ -5972,7 +5952,7 @@ msgstr "Tanggal" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Hapus Snapshot" @@ -6020,57 +6000,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "dibuat manual" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "linimasa" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Kelola Snapshot" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Snapshot yang dibuat." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Konfigurasi snapshot penyimpanan diperbarui" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Galat {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Menghapus snapshot yang dipilih" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Snapshot sedang digunakan. Silakan coba lagi nanti." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Sistem harus dimulai ulang untuk menyelesaikan rollback." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Rollback ke Snapshot" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6078,7 +6058,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Server Secure Shell (SSH)" @@ -6115,14 +6095,6 @@ msgstr "Algoritma" msgid "Fingerprint" msgstr "Sidik Jari" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -6135,7 +6107,7 @@ msgstr "Masuk" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6143,143 +6115,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Penyimpanan" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bytes" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Operasi gagal." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Operasi telah dibatalkan." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Perangkat belum terpasang." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Nama direktori tidak valid." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Direktori ini tidak ada." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Direktori" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Subdirektori (opsional)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Bagikan" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Direktori lainnya (silakan tulis)" @@ -6313,7 +6285,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6331,30 +6303,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6362,7 +6334,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6374,20 +6346,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6396,47 +6368,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6538,13 +6510,13 @@ msgstr "Layanan" msgid "Ports" msgstr "Port" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Terjadi kesalahan selama konfigurasi." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6602,14 +6574,14 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "It can be accessed by any user on {box_name} " @@ -6621,17 +6593,17 @@ msgstr "" "Itu dapat diakses oleh pengguna apa pun pada " "{box_name} milik kelompok admin." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6640,12 +6612,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6653,8 +6625,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -6662,28 +6634,28 @@ msgstr "" msgid "Software Update" msgstr "URL Server diperbarui" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox Updated" msgstr "FreedomBox" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Pembaruan distribusi dimulai" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6847,53 +6819,53 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Pembaruan distribusi dinonaktifkan" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Pembaruan distribusi dinonaktifkan" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Distribution upgrade disabled" msgid "Starting distribution upgrade test." msgstr "Pembaruan distribusi dinonaktifkan" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6901,15 +6873,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6927,23 +6899,23 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 #, fuzzy #| msgid "Administrator Account" msgid "Authorization Password" msgstr "Akun Administrator" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Kata sandi tidak valid." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6952,12 +6924,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Gagal membuat pengguna LDAP. {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Gagal menambahkan pengguna baru ke kelompok {group}: {error}" @@ -6973,43 +6945,43 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 #, fuzzy #| msgid "Failed to add new user to admin group." msgid "Failed to change user status." msgstr "Gagal menambahkan pengguna baru ke kelompok admin." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Gagal menambahkan pengguna baru ke kelompok admin. {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -7026,12 +6998,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -7071,17 +7043,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -7112,34 +7084,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Insan {user} dipangkar." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7466,7 +7438,7 @@ msgstr "Hapus Koneksi" msgid "Server deleted." msgstr "{name} dihapus." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7475,7 +7447,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7484,28 +7456,28 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 #, fuzzy #| msgid "Address" msgid "WordPress" msgstr "Address" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Wiki and Blog" msgid "Website and Blog" @@ -7523,7 +7495,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7536,7 +7508,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7544,11 +7516,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7598,114 +7570,108 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "Kesalahan saat cadangan" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "memasang" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "mengunduh" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Instal aplikasi" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Kesalahan Pemasangan aplikasi: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Kesalahan Pemasangan aplikasi: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Kesalahan pemasangan aplikasi: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Kesalahan pemasangan aplikasi: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikasi telah terpasang." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Pembaharuan Terakhir" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Instal aplikasi" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Kesalahan Pemasangan aplikasi: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Kesalahan pemasangan aplikasi: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikasi telah terpasang." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7757,53 +7723,54 @@ msgstr "Pemasangan" msgid "Service %(service_name)s is not running." msgstr "Layanan %(service_name)s tidak berjalan." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Fungsionalitas inti dan antarmuka web untuk %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Beranda" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Beranda" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Aplikasi" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Apps" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " sistem" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Sistem" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Ganti kata sandi" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Matikan" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Keluar" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Pilih bahasa" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Masuk" @@ -8074,6 +8041,40 @@ msgstr "" msgid "Gujarati" msgstr "Bahasa Gujarat" +#~ msgid "Enable DNSSEC" +#~ msgstr "Aktifkan DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Aktifkan ekstensi keamanan nama domain" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Daemon firewall tidak berjalan. Silakan jalankan. Firewall datang " +#~ "diaktifkan secara default pada %(box_name)s. Pada sistem berbasis debian " +#~ "apa pun (seperti %(box_name)s) Anda dapat menjalankannya menggunakan " +#~ "perintah 'Service firewalld start' atau Dalam hal sistem dengan systemd " +#~ "'systemctl mulai firewalld'." + +#~ msgid "Migrate to ECC" +#~ msgstr "Migrasi ke ECC" + +#~ msgid "Migrate" +#~ msgstr "Migrasi" + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "Kesalahan saat cadangan" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Fungsionalitas inti dan antarmuka web untuk %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Koneksi Jaringan" diff --git a/plinth/locale/it/LC_MESSAGES/django.po b/plinth/locale/it/LC_MESSAGES/django.po index 5bbac2b3c..6f90faf0e 100644 --- a/plinth/locale/it/LC_MESSAGES/django.po +++ b/plinth/locale/it/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Italian calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Nome della nuova libreria" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Esiste già una libreria con questo nome." @@ -1094,20 +1087,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "Cancella libreria %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Libreria creata." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Si è verificato un errore durante la creazione della libreria." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} cancellato." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Non è stato possibile cancellare {name}: {error}" @@ -1152,7 +1145,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Amministrazione Server" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1160,18 +1153,18 @@ msgstr "" "Qui si possono impostare alcune opzioni di configurazione generali come " "hostname, nome di dominio, home page del webserver ecc." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Configurazione Generale" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Configura" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1292,50 +1285,50 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Errore impostazione hostname: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 #, fuzzy msgid "Hostname set" msgstr "Imposta hostname" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Errore impostazione nome di dominio: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 #, fuzzy msgid "Domain name set" msgstr "Imposta nome di dominio" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Errore impostazione home page server web: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 #, fuzzy msgid "Webserver home page set" msgstr "Impostato home page del webserver" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Errore nel cambio di modalità avanzata: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Visualizzazione di applicazioni e funzionalità avanzate" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Nascondere applicazioni e funzionalità avanzate" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1343,7 +1336,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Client DNS Dinamico" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Nome Dominio Dinamico" @@ -1743,7 +1736,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1813,7 +1806,7 @@ msgstr "Cancella connessione" msgid "Already up-to-date" msgstr "Abilita l'aggiornamento automatico" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1821,7 +1814,7 @@ msgstr "" "XMPP è un protocollo di comunicazione aperto e standardizzato. Qui puoi " "eseguire e configurare il tuo server XMPP, chiamato ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client da ogni utente con un login " "{box_name} ." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Server Chat" @@ -1967,14 +1960,14 @@ msgstr "" "impostare il tuo dominio nel sistema . Configura " "la pagina ." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1982,7 +1975,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1992,13 +1985,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2127,7 +2120,7 @@ msgstr "Porta" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2139,7 +2132,7 @@ msgstr "" "adeguatamente configurato riduce i rischi di attacchi informatici dalla rete " "Internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall" @@ -2159,53 +2152,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Porta {name} ({details}) non disponibile per reti esterne" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Il demone del firewall non è in esecuzione. Abilitalo per favore. Il " -"firewall è attivato di predefinito nel %(box_name)s. Sui qualsiasi sistema " -"basato su Debian (come %(box_name)s) è possibile eseguirlo usando il comando " -"'service firewall start' o nol caso di un sistema con systemd 'systemctl " -"start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Servizio/Porta" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Abilitato" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Disabilitato" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Permesso" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Permesso (solo internamente)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Permesso (solo esternamente)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Bloccato" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2215,13 +2194,13 @@ msgstr "" "abilitato anche sul firewall, e quando lo disabiliti, viene disabilitato " "anche nel firewall." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2272,7 +2251,7 @@ msgstr "Avvia Configurazione" msgid "Setup Complete" msgstr "Configurazione Completata" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2291,7 +2270,7 @@ msgstr "" "grafici disponibili. E puoi condividere il tuo codice con persone in tutto " "il mondo." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2299,71 +2278,71 @@ msgstr "" "Per saperne di più su come usare Git visita Git tutorial." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Accesso in lettura e scrittura ai repository Git" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Semplice Git Hosting" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "URL del repository non valido." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Nome del deposito non valido." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Nome di un nuovo repository o URL per importare un repository esistente." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Descrizione del repository" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Opzionale, per la visualizzazione su Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Nome del proprietario del deposito" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Deposito privato" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Consentire l'accesso a questo repository solo agli utenti autorizzati." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Esiste già un deposito con questo nome." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Nome del deposito" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 #, fuzzy msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "Una stringa alfanumerica che identifica in modo univoco un deposito." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Default" msgid "Default branch" msgstr "Ramo di default" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2407,19 +2386,19 @@ msgstr "Cancellare Git Repository %(name)s" msgid "Delete this repository permanently?" msgstr "Cancellare questo repository in modo permanente?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Repository creato." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Si è verificato un errore durante la creazione del repository." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Repository modificato." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Modifica repository" @@ -2789,7 +2768,7 @@ msgstr "Sul {box_name}" msgid "{box_name} Manual" msgstr "Manuale {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 #, fuzzy msgid "" "The Invisible Internet Project is an anonymous network layer intended to " @@ -2802,7 +2781,7 @@ msgstr "" "l'anonimato inviando traffico criptato attraverso una rete di volontari " "distribuiti in tutto il mondo." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2810,7 +2789,7 @@ msgstr "" "Si possono trovare maggiori informazioni su I2P sul sito web del loro progetto." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 #, fuzzy msgid "" "The first visit to the provided web interface will initiate the " @@ -2819,20 +2798,20 @@ msgstr "" "La prima visita all'interfaccia web fornita inizierà il processo di " "configurazione." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Gestione dell'applicazione I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 #, fuzzy msgid "Anonymity Network" msgstr "Rete di anonimato" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "Proxy I2P" @@ -2880,7 +2859,7 @@ msgstr "" "peer-to-peer. Scaricate i file aggiungendo torrenti o create un nuovo " "torrent per condividere un file." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2890,7 +2869,7 @@ msgstr "" "markup di linguaggio leggeri, incluso Markdown, e comuni funzionalità di " "blogging come commenti e feed RSS." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2904,15 +2883,15 @@ msgstr "" "\"{users_url}\">Configurazione Utente è possibile cambiare questi " "permessi o aggiungere nuovi utenti." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki e Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Vedi e modifica le applicazioni wiki" @@ -2968,42 +2947,42 @@ msgstr "" "Quest'azione cancellerà tutti i post, le pagine e i commenti, incluse le " "revisione storiche. Cancellare questo wiki o blog permanentente?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Creato wiki {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Non è stato possibile creare l'wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Creato blog {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Non è stato possibile creare il blog: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} cancellato." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Non è stato possibile cancellare {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 #, fuzzy msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted è un server per Gobby, un editore testuale comunitario." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, fuzzy, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3014,11 +2993,11 @@ msgstr "" "desktop e installarlo. Dopo avviare Hobby e seleziona \"Connect to Server\" " "e entrare nel tuo nome di dominio {box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby Server" @@ -3066,7 +3045,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Informazioni sulla licenza JavaScript" @@ -3086,7 +3065,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Client" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3101,7 +3080,7 @@ msgstr "" "disposizione. Ci riesce provando esso stesso di essere il proprietario del " "dominio a Let's Encrypt, un'autorità di certificazione (CA)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3114,15 +3093,15 @@ msgstr "" "letsencrypt.org/repository/\"> i termini dell'accordo dell'abbonato Let's " "Encrypt prima utilizzare questo servizio." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Certificati" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3187,7 +3166,7 @@ msgstr "" "Non sono stati configurati domini. Configurare i " "domini per poter ottenere i certificati per essi." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3196,34 +3175,34 @@ msgstr "" "Certificato revocato correttamente per il dominio {domain}. Ciò può " "richiedere alcuni minuti per avere effetto." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Revoca certificato fallita per il dominio {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Certificato correttamente ottenuto per il dominio {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Rilascio certificato fallito per il dominio {domain}:{error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Certificato cancellato correttamente per il dominio {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Cancellazione certificato fallita per il dominio {domain}:{error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3240,14 +3219,14 @@ msgstr "" "Gli utenti di un certo server Matrix possono comunicare con gli altri utenti " "attestati su tutti gli altri server Matrix tramite federazione." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3349,7 +3328,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3362,7 +3341,7 @@ msgstr "" "stile wiki, per prendere note o per collaborare con degli amici su dei " "progetti." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3377,7 +3356,7 @@ msgstr "" "MediaWiki, andando nella pagina Speciale:CreateAccount." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3385,12 +3364,12 @@ msgstr "" "Chiunque con un collegamento a questo wiki può leggerlo. Solo gli utenti " "autenticati possono apportare modifiche ai contenuti." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3472,39 +3451,39 @@ msgstr "Password aggiornata" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Registrazioni pubbliche abilitate" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Registrazioni pubbliche disabilitate" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 #, fuzzy msgid "Private mode enabled" msgstr "Modo privato abilitato" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 #, fuzzy msgid "Private mode disabled" msgstr "Modo privato disabilitato" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Tema predefinito modificato" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy msgid "Domain name updated" msgstr "Imposta nome di dominio" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy msgid "Site name updated" msgstr "Imposta nome di dominio" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3517,11 +3496,11 @@ msgstr "" "porta predefinita (30000). Per connettersi al server, è necessario un client Minetest." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Block Sandbox" @@ -3575,7 +3554,7 @@ msgstr "" msgid "Address" msgstr "Indirizzo" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3752,19 +3731,19 @@ msgstr "Secure Shell" msgid "Services" msgstr "Servizi" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Reti" @@ -4134,7 +4113,7 @@ msgstr "Modifica Connessione" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Modifica" @@ -4240,7 +4219,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Metodo" @@ -4256,7 +4235,7 @@ msgstr "Server DNS" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Default" @@ -4269,7 +4248,7 @@ msgid "This connection is not active." msgstr "Questa connessione non è attiva." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Sicurezza" @@ -4814,7 +4793,7 @@ msgstr "Connessione {name} cancellata." msgid "Failed to delete connection: Connection not found." msgstr "Cancellazione connessione fallita: connessione non trovata." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4831,20 +4810,20 @@ msgstr "" "accedere al resto della rete Internet via {box_name} per una maggiore " "sicurezza e anonimità." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Rete virtuale privata" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4855,48 +4834,21 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profilo" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Per connetterti alla VPN del %(box_name)s, hai bisogno di scaricare un " @@ -4905,17 +4857,18 @@ msgstr "" "Cliccate su \"Per saperne di più...\" qui sopra per i clienti consigliati e " "le istruzioni su come configurarli." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Il profilo è specifico per ogni utente del %(box_name)s. Mantienilo segreto." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Scarica il mio profilo" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4928,18 +4881,18 @@ msgstr "" "il tuo {box_name} non è raggiungibile dall'esterno. Questo include le " "situazioni seguenti:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} è valle di un firewall ristretto." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} è connesso ad un router (wireless) di cui non hai il controllo." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -4947,7 +4900,7 @@ msgstr "" "Il tuo ISP non ti assegna un IP pubblico ma ti fornisce una connessione " "tramite NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -4955,11 +4908,11 @@ msgstr "" "Il tuo ISP non ti fornisce un IP statico e il tuo IP cambia ogni volta che " "ti connetti a Internet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Il tuo ISP limita le connessioni in entrata." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4973,23 +4926,23 @@ msgstr "" "futuro potrebbe essere possibile usare la {box_name} del tuo amico per " "questo." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Visibilità Pubblica" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "Dominio PageKite" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Dominio server" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -4997,31 +4950,31 @@ msgstr "" "Selezione il tuo server pagekite. Imposta \"pagekite.net\" per usare il " "server predefinito di pagekite.net." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Porta server" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Porta del tuo server pagekite (predefinita: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Nome Kite" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Esempio: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Nome Kite invalido" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Segreto Kite" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5029,35 +4982,35 @@ msgstr "" "Un segreto associate col kite o il segreto predefinito del tuo profile nel " "caso non sia state impostato nel kite." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protocollo" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "porta esterna (frontend)" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "porta interna (freedombox)" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Abilita Sottodomini" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Cancella servizio personalizzato" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Questo servizio è già disponibile come servizio standard." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Servizio personalizzato aggiunto" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Questo servizio è già presente" @@ -5095,29 +5048,29 @@ msgstr "" "Per esempio, è noto che HTTPS, in porte diverse dalla 443, può causare " "problemi." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Server Web (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Il sito sarà disponibile su http{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Server Web (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Il sito sarà disponibile au HTTPS://{0}{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5164,8 +5117,8 @@ msgstr "" "la possibilità di aspettare che fimisca prima di spegnere o riavviare il " "sistema." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -5216,6 +5169,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Spegni Ora" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5262,7 +5248,7 @@ msgstr "Web Proxy" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Accesso {url} con proxy {proxy} su tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5279,7 +5265,7 @@ msgstr "" "possibile usare uno o più client Quassel desktop o mobile, per connettersi e " "disconnettersi su di esso." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your desktop e mobile." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "Client IRC" @@ -5303,7 +5289,7 @@ msgstr "Client IRC" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5318,19 +5304,19 @@ msgstr "" "un'applicazione client supportata. È possibile accedere a Radicale da " "ogni utente con un profilo {box_name}." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Calendario e Rubrica" @@ -5398,7 +5384,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -5470,7 +5456,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5483,13 +5469,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5498,31 +5484,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Stoccaggio dei file di rete" @@ -5600,15 +5586,15 @@ msgstr "Nome Share" msgid "Action" msgstr "Azione" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Apri Share" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5634,51 +5620,51 @@ msgstr "Share disabilitato." msgid "Error disabling share: {error_message}" msgstr "Errore installazione applicazione: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5833,14 +5819,14 @@ msgstr "" msgid "Shaarlier" msgstr "Shaarli" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5849,97 +5835,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Share pubblico" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5976,26 +5962,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6003,14 +5989,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -6104,7 +6090,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -6152,58 +6138,58 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "creato manualmente" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 #, fuzzy msgid "Deleted selected snapshots" msgstr "Istantanee selezionate cancellate" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6211,7 +6197,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -6244,14 +6230,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -6264,7 +6242,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6272,144 +6250,144 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 #, fuzzy msgid "The device is already unmounting." msgstr "Il dispositivo sta già smontando." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Il dispositivo è già montato." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Hostname non valido." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Partage" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6443,7 +6421,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6461,30 +6439,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6492,7 +6470,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6504,20 +6482,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6526,47 +6504,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6664,11 +6642,11 @@ msgstr "Servizio Onion" msgid "Ports" msgstr "Ports" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Aggiornamento della configurazione" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6726,14 +6704,14 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Tiny Tiny RSS can be accessed by any utente con un account su {box_name}." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6763,12 +6741,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6776,33 +6754,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Aggiornamento software" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox aggiornato" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6953,51 +6931,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7005,15 +6983,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -7031,21 +7009,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Password di autorizzazione" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Password non valida." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7054,12 +7032,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Fallito l'inserimento di un nuovo utente nel gruppo {group}: {error}" @@ -7075,41 +7053,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Aggiunta del nuovo utente al gruppo admin fallita: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Fallito la limitazione dell'accesso alla console: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -7126,12 +7104,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -7169,17 +7147,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -7210,34 +7188,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7546,7 +7524,7 @@ msgstr "Cancella Connessione a server" msgid "Server deleted." msgstr "Server cancellato." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7555,7 +7533,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7564,26 +7542,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Sito web e blog" @@ -7597,7 +7575,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7610,7 +7588,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7618,11 +7596,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7673,114 +7651,108 @@ msgstr "" msgid "Finished: {name}" msgstr "Servizio disabilitato: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "Errore durante il backup" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Installa App" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Errore installazione applicazione: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Errore installazione applicazione: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Errore durante l'installazione dell'applicazione: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Errore durante l'installazione dell'applicazione: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Applicazione installata." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Ultimo aggiornamento" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Installa App" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Errore installazione applicazione: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Errore durante l'installazione dell'applicazione: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Applicazione installata." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7836,53 +7808,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -8147,6 +8120,30 @@ msgstr "" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Abilita DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Abilita Domain Name System Security Extensions" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Il demone del firewall non è in esecuzione. Abilitalo per favore. Il " +#~ "firewall è attivato di predefinito nel %(box_name)s. Sui qualsiasi " +#~ "sistema basato su Debian (come %(box_name)s) è possibile eseguirlo usando " +#~ "il comando 'service firewall start' o nol caso di un sistema con systemd " +#~ "'systemctl start firewalld'." + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "Errore durante il backup" + #~ msgid "Network Connections" #~ msgstr "Connessione di rete" diff --git a/plinth/locale/ja/LC_MESSAGES/django.po b/plinth/locale/ja/LC_MESSAGES/django.po index a414473d5..fb5b524f2 100644 --- a/plinth/locale/ja/LC_MESSAGES/django.po +++ b/plinth/locale/ja/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-05-20 12:32+0000\n" "Last-Translator: Jacque Fresco \n" "Language-Team: Japanese calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1021,20 +1014,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1072,24 +1065,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1185,47 +1178,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1233,7 +1226,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1463,11 +1456,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1579,7 +1572,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1634,13 +1627,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1762,14 +1755,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1777,7 +1770,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1787,13 +1780,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1918,7 +1911,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1926,7 +1919,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1946,61 +1939,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2046,7 +2030,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2057,73 +2041,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2167,19 +2151,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2472,7 +2456,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2480,31 +2464,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2541,14 +2525,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2557,15 +2541,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2619,41 +2603,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2661,11 +2645,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2711,7 +2695,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2729,7 +2713,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2739,7 +2723,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2747,15 +2731,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2818,41 +2802,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2862,14 +2846,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2950,7 +2934,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2958,7 +2942,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2967,18 +2951,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3047,35 +3031,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3084,11 +3068,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3133,7 +3117,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3292,19 +3276,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3650,7 +3634,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3755,7 +3739,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3771,7 +3755,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3784,7 +3768,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4320,7 +4304,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4331,20 +4315,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4354,61 +4338,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4417,33 +4369,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4452,87 +4404,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4566,29 +4518,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4630,8 +4582,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4673,6 +4625,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4704,7 +4687,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4715,7 +4698,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4735,7 +4718,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4745,19 +4728,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4816,7 +4799,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4883,7 +4866,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4896,13 +4879,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4911,31 +4894,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5013,15 +4996,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5047,51 +5030,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5244,14 +5227,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5260,97 +5243,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5387,26 +5370,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5414,14 +5397,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5515,7 +5498,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5563,57 +5546,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5621,7 +5604,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5654,14 +5637,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5674,7 +5649,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5682,143 +5657,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5852,7 +5827,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5870,30 +5845,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5901,7 +5876,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5913,20 +5888,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5935,47 +5910,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6073,11 +6048,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6129,31 +6104,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6161,12 +6136,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6174,33 +6149,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6348,51 +6323,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6400,15 +6375,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6426,21 +6401,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6449,12 +6424,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6470,41 +6445,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6521,12 +6496,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6564,17 +6539,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6605,34 +6580,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6941,7 +6916,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6950,7 +6925,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6959,26 +6934,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6992,7 +6967,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7005,7 +6980,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7013,11 +6988,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7066,96 +7041,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7206,53 +7177,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "アプリ" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/kn/LC_MESSAGES/django.po b/plinth/locale/kn/LC_MESSAGES/django.po index e775b4750..11a48deb7 100644 --- a/plinth/locale/kn/LC_MESSAGES/django.po +++ b/plinth/locale/kn/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2020-07-16 16:41+0000\n" "Last-Translator: Yogesh \n" "Language-Team: Kannada calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1021,20 +1014,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1072,24 +1065,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1185,47 +1178,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1233,7 +1226,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1463,11 +1456,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1579,7 +1572,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1634,13 +1627,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1762,14 +1755,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1777,7 +1770,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1787,13 +1780,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1918,7 +1911,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1926,7 +1919,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1946,61 +1939,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2046,7 +2030,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2057,73 +2041,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2167,19 +2151,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2472,7 +2456,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2480,31 +2464,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2541,14 +2525,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2557,15 +2541,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2619,41 +2603,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2661,11 +2645,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2711,7 +2695,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2729,7 +2713,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2739,7 +2723,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2747,15 +2731,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2818,41 +2802,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2862,14 +2846,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2950,7 +2934,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2958,7 +2942,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2967,18 +2951,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3047,35 +3031,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3084,11 +3068,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3133,7 +3117,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3292,19 +3276,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3650,7 +3634,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3755,7 +3739,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3771,7 +3755,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3784,7 +3768,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4320,7 +4304,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4331,20 +4315,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4354,61 +4338,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4417,33 +4369,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4452,87 +4404,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4566,29 +4518,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4630,8 +4582,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4673,6 +4625,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4704,7 +4687,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4715,7 +4698,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4735,7 +4718,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4745,19 +4728,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4816,7 +4799,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4883,7 +4866,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4896,13 +4879,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4911,31 +4894,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5013,17 +4996,17 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "ಫ್ರೀಡಂಬಾಕ್ಸ್" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5049,51 +5032,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5246,14 +5229,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5262,97 +5245,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5389,26 +5372,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5416,14 +5399,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5517,7 +5500,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5565,57 +5548,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5623,7 +5606,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5656,14 +5639,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5676,7 +5651,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5684,143 +5659,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5854,7 +5829,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5872,30 +5847,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5903,7 +5878,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5915,20 +5890,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5937,47 +5912,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6075,11 +6050,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6131,31 +6106,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6163,12 +6138,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6176,33 +6151,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6350,51 +6325,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6402,15 +6377,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6428,21 +6403,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6451,12 +6426,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6472,41 +6447,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6523,12 +6498,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6566,17 +6541,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6607,34 +6582,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6943,7 +6918,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6952,7 +6927,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6961,26 +6936,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6994,7 +6969,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7007,7 +6982,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7015,11 +6990,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7068,96 +7043,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7208,53 +7179,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/lt/LC_MESSAGES/django.po b/plinth/locale/lt/LC_MESSAGES/django.po index 621b39731..866693cd2 100644 --- a/plinth/locale/lt/LC_MESSAGES/django.po +++ b/plinth/locale/lt/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Lithuanian calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1023,20 +1016,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1074,24 +1067,24 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1187,47 +1180,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1235,7 +1228,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1465,11 +1458,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1581,7 +1574,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1636,13 +1629,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1764,14 +1757,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1779,7 +1772,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1789,13 +1782,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1920,7 +1913,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1928,7 +1921,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1948,61 +1941,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2048,7 +2032,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2059,73 +2043,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2169,19 +2153,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2474,7 +2458,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2482,31 +2466,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2543,14 +2527,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2559,15 +2543,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2621,41 +2605,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2663,11 +2647,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2713,7 +2697,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2731,7 +2715,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2741,7 +2725,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2749,15 +2733,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2820,41 +2804,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2864,14 +2848,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -2952,7 +2936,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2960,7 +2944,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2969,18 +2953,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3049,35 +3033,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3086,11 +3070,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3135,7 +3119,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3294,19 +3278,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3652,7 +3636,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3757,7 +3741,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3773,7 +3757,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3786,7 +3770,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4322,7 +4306,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4333,20 +4317,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4356,61 +4340,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4419,33 +4371,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4454,87 +4406,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4568,29 +4520,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4632,8 +4584,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4675,6 +4627,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4706,7 +4689,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4717,7 +4700,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4737,7 +4720,7 @@ msgstr "" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4747,19 +4730,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4818,7 +4801,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4885,7 +4868,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4898,13 +4881,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4913,31 +4896,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5015,15 +4998,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5049,51 +5032,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5246,14 +5229,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5262,97 +5245,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5389,26 +5372,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5416,14 +5399,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5517,7 +5500,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5565,57 +5548,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5623,7 +5606,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5656,14 +5639,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5676,7 +5651,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5684,143 +5659,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5854,7 +5829,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5872,30 +5847,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5903,7 +5878,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5915,20 +5890,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5937,47 +5912,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6075,11 +6050,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6131,31 +6106,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6163,12 +6138,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6176,33 +6151,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6350,51 +6325,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6402,15 +6377,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6428,21 +6403,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6451,12 +6426,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6472,41 +6447,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6523,12 +6498,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6566,17 +6541,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6607,34 +6582,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6943,7 +6918,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6952,7 +6927,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6961,26 +6936,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6994,7 +6969,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7007,7 +6982,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7015,11 +6990,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7068,96 +7043,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7208,53 +7179,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/lv/LC_MESSAGES/django.po b/plinth/locale/lv/LC_MESSAGES/django.po index 2e7ba7572..fb96b5847 100644 --- a/plinth/locale/lv/LC_MESSAGES/django.po +++ b/plinth/locale/lv/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:20+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Latvian calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1022,20 +1015,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1073,24 +1066,24 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1186,47 +1179,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1234,7 +1227,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1464,11 +1457,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1580,7 +1573,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1635,13 +1628,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1763,14 +1756,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1778,7 +1771,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1788,13 +1781,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1919,7 +1912,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1927,7 +1920,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1947,61 +1940,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2047,7 +2031,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2058,73 +2042,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2168,19 +2152,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2473,7 +2457,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2481,31 +2465,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2542,14 +2526,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2558,15 +2542,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2620,41 +2604,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2662,11 +2646,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2712,7 +2696,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2730,7 +2714,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2740,7 +2724,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2748,15 +2732,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2819,41 +2803,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2863,14 +2847,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -2951,7 +2935,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2959,7 +2943,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2968,18 +2952,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3048,35 +3032,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3085,11 +3069,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3134,7 +3118,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3293,19 +3277,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3651,7 +3635,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3756,7 +3740,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3772,7 +3756,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3785,7 +3769,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4321,7 +4305,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4332,20 +4316,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4355,61 +4339,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4418,33 +4370,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4453,87 +4405,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4567,29 +4519,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4631,8 +4583,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4674,6 +4626,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4705,7 +4688,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4716,7 +4699,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4736,7 +4719,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4746,19 +4729,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4817,7 +4800,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4884,7 +4867,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4897,13 +4880,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4912,31 +4895,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5014,15 +4997,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5048,51 +5031,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5245,14 +5228,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5261,97 +5244,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5388,26 +5371,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5415,14 +5398,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5516,7 +5499,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5564,57 +5547,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5622,7 +5605,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5655,14 +5638,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5675,7 +5650,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5683,143 +5658,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5853,7 +5828,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5871,30 +5846,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5902,7 +5877,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5914,20 +5889,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5936,47 +5911,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6074,11 +6049,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6130,31 +6105,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6162,12 +6137,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6175,33 +6150,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6349,51 +6324,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6401,15 +6376,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6427,21 +6402,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6450,12 +6425,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6471,41 +6446,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6522,12 +6497,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6565,17 +6540,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6606,34 +6581,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6942,7 +6917,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6951,7 +6926,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6960,26 +6935,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6993,7 +6968,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7006,7 +6981,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7014,11 +6989,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7067,96 +7042,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7207,53 +7178,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/nb/LC_MESSAGES/django.po b/plinth/locale/nb/LC_MESSAGES/django.po index f32100d14..8531ee367 100644 --- a/plinth/locale/nb/LC_MESSAGES/django.po +++ b/plinth/locale/nb/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-10-09 07:43+0000\n" "Last-Translator: Petter Reinholdtsen \n" "Language-Team: Norwegian Bokmål calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1058,29 +1051,29 @@ msgstr "" "Kun brukere som tilhører calibre-gruppen vil ha tilgang til " "programmet. Alle brukere med tilgang kan bruke alle bibliotekene." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Bruk calibre ebokbibliotek" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "E-bok-bibliotek" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Navn på nytt bibliotek" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Det finnes allerede et bibliotek med dette navnet." @@ -1128,22 +1121,22 @@ msgstr "Gå til biblioteket %(library)s" msgid "Delete library %(library)s" msgstr "Slett biblioteket %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Bibliotek opprettet." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 #, fuzzy #| msgid "An error occurred during configuration." msgid "An error occurred while creating the library." msgstr "En feil oppsto under konfigureringen." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "Slettet {name}." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Kunne ikke slette {name}: {error}" @@ -1191,7 +1184,7 @@ msgstr "Styrhus" msgid "Server Administration" msgstr "Tjeneradministrasjon" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1199,18 +1192,18 @@ msgstr "" "Her kan du sette noen generelle oppsettsvalg som vertsnavn, domenenavn, " "vevtjener-hjemmeside, etc." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Generelt oppsett" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Oppsett" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1323,47 +1316,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Feil ved setting av vertsnavn: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Vertsnavn satt" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Feil ved innstilling/setting av domenenavn: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Domenenavn satt" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Feil ved setting av nettstedets hjemmeside: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Webtjenerforside satt" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Feil ved bytte til avansert modus: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Viser avanserte programmer og funksjoner" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Viser ikke avanserte programmer og funksjoner" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1375,7 +1368,7 @@ msgstr "" "kommunikasjonstjenere kan bruke det for å etablere en samtale mellom parter " "som ellers ikke ville kunne kontakte hverandre." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse eller ejabberd må " "settes opp med detaljene herfra." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP-hjelper" @@ -1449,11 +1442,11 @@ msgstr "Feil ved setting av tidssone: {exception}" msgid "Time zone set" msgstr "Tidssone satt" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge er en BitTorrent-klient som har et Web-grensesnitt." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1461,16 +1454,16 @@ msgstr "" "Standardpassordet er «deluge», men du bør logge inn og endre det umiddelbart " "etter at denne tjenesten er aktivert." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Last ned filer ved bruk av BitTorrent-programmer" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent nett-klient" @@ -1600,7 +1593,7 @@ msgstr "Resultat" msgid "Diagnostic Test" msgstr "Diagnostikktest" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1611,7 +1604,7 @@ msgstr "" "eks. hver 24 t), kan det være vanskelig for andre å finne deg på Internett. " "Dette vil hindre andre i å finne tjenester som tilbys av dette {box_name}et." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1628,7 +1621,7 @@ msgstr "" "tjeneren tildele DNS-navnet ditt til den nye IP-en. Hvis noen fra Internett " "ber om ditt DNS-navn, vil de da få svar med din gjeldende IP-adresse." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 #, fuzzy #| msgid "" #| "If you are looking for a free dynamic DNS account, you may find a free " @@ -1648,11 +1641,11 @@ msgstr "" "baserte oppdateringstjenester her freedns.afraid.org ." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Dynamisk DNS-klient" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Dynamisk domenenavn" @@ -1788,7 +1781,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1857,7 +1850,7 @@ msgstr "Slett tilkobling" msgid "Already up-to-date" msgstr "Auto-oppdatering" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1865,7 +1858,7 @@ msgstr "" "XMPP er en åpen og standardisert kommunikasjonsprotokoll. Her kan du kjøre " "og konfigurere din XMPP-tjener, kalt ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientbruker med innlogging på " "{box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Nettprat-tjener" @@ -2009,7 +2002,7 @@ msgstr "" "se slik ut: username@%(domainname)s. Du kan sette opp ditt domene på " "systemsiden Configure ." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -2019,7 +2012,7 @@ msgstr "" "Rspamd. Postfix sender og mottar e-post. Dovecot gir e-postklienter tilgang " "til din postkasse ved hjelp av IMAP og POP3. Rspamd håndterer spam." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2032,7 +2025,7 @@ msgstr "" "blokkeringen etter eksplisitte henvendelser. Se manualsiden for mer " "informasjon." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2042,13 +2035,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2189,7 +2182,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2200,7 +2193,7 @@ msgstr "" "utgående nettverkstrafikk på din {box_name}. Å holde en brannmur aktivert og " "riktig konfigurert, reduserer risikoen for sikkerhetstrusler fra Internett." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Brannmur" @@ -2220,52 +2213,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port {name} ({details}) er utilgjengelig for eksterne nettverk" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Brannmur-bakgrunnsprosessen kjører ikke. Den må kjøre. Brannmuren kommer som " -"standard aktivert på %(box_name)s. På et Debian-basert system (slik som " -"%(box_name)s), kan du kjøre den med kommandoen «service firewalld start», " -"eller alternativt i et system med systemd, «systemctl start firewalld»." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Tjeneste/Port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Aktivert" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Deaktivert" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Tillatt" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Tillatt (kun internt)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Tillatt (kun eksternt)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Blokkert" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2275,13 +2255,13 @@ msgstr "" "også tillatt i brannmuren, og når du deaktiverer en tjeneste, er den også " "deaktivert i brannmuren." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Avansert" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2334,7 +2314,7 @@ msgstr "Gå i gang med oppsett" msgid "Setup Complete" msgstr "Oppsett ferdig" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2352,7 +2332,7 @@ msgstr "" "flerfoldige grafiske klienter. Du kan også dele koden med folk rundt omkring " "i verden." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2360,27 +2340,27 @@ msgstr "" "For å lære mer om bruk av Git, besøk Git-veiledningen." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Lese- og skrivetilgang til Git-kodelagre" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Enkelt Git-vertsskap" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Ugyldig kodelager-nettadresse." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Ugyldig kodelagernavn." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 #, fuzzy #| msgid "" #| "Repository path is neither empty nor is an existing backups repository." @@ -2389,38 +2369,38 @@ msgstr "" "Pakkebrønnssti er hverken tom eller en eksisterende " "sikkerhetskopieringspakkebrønn." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Beskrivelse av kodelageret" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 #, fuzzy msgid "Optional, for displaying on Gitweb." msgstr "Valgfritt, for visning på Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Kodelagereierens navn" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Privat kodelager" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Gi kun autoriserte brukere tilgang til dette kodelageret." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 #, fuzzy #| msgid "A share with this name already exists." msgid "A repository with this name already exists." msgstr "En deling ved dette navnet finnes allerede." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Navn på kodelager" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 #, fuzzy #| msgid "" #| "A lowercase alpha-numeric string that uniquely identifies a share. " @@ -2428,13 +2408,13 @@ msgstr "Navn på kodelager" msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "En alfanumerisk streng som unikt identifiserer et kodelager." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Default Skin" msgid "Default branch" msgstr "Forvalgt drakt" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb biser dette som forvalgt forgrening." @@ -2479,21 +2459,21 @@ msgstr "Slett Git-kodelager %(name)s" msgid "Delete this repository permanently?" msgstr "Slett dette kodelageret for godt?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Kodelager opprettet." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 #, fuzzy #| msgid "An error occurred during configuration." msgid "An error occurred while creating the repository." msgstr "En feil oppsto under konfigureringen." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Kodelager redigert.." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Rediger kodelager" @@ -2860,7 +2840,7 @@ msgstr "Om {box_name}" msgid "{box_name} Manual" msgstr "{box_name} Manual" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2872,7 +2852,7 @@ msgstr "" "anonymitet ved å sende kryptert trafikk gjennom et frivilligdrevet nettverk " "distribuert verden om." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2880,7 +2860,7 @@ msgstr "" "For mer informasjon om I2P, sjekk deres nettside." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2888,19 +2868,19 @@ msgstr "" "Den første til å besøke det oppsatte nettgrensesnittet vil igangsette " "oppsettsprosessen." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Håndter I2P-program" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Anonymitetsnettverk" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P-mellomtjener" @@ -2946,7 +2926,7 @@ msgstr "" "likemannsnettverk. Last ned filer ved å legge til torrenter, eller opprett " "en ny torrent for å dele ei fil." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2956,7 +2936,7 @@ msgstr "" "lettvektsoppmerkingsspråk, inkludert Markdown, og vanlige bloggfunksjoner " "som kommentarer og RSS-informasjonskilder." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2970,15 +2950,15 @@ msgstr "" "\"{users_url}\">brukeroppsettet kan du endre disse tilgangene eller " "legge til nye brukere." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki og Blogg" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Vis og rediger wiki-programmer" @@ -3034,41 +3014,41 @@ msgstr "" "Denne handlingen vil fjerne alle poster, sider og kommentarer inkludert " "revisjonshistorien. Skal denne wiki-en eller bloggen slettes for godt?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Opprettet wiki {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Kunne ikke opprette wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Opprettet blogg {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Kunne ikke lage blogg: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} slettet." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Kunne ikke slette {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted er en tjener for Gobby, en samskrivende teksteditor." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3079,11 +3059,11 @@ msgstr "" "skrivebordsklient og installer den. Deretter starter du Gobby og velger " "«Koble til tjener», og skriver inn domenenavnet til din {box_name} ." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby-tjener" @@ -3131,7 +3111,7 @@ msgstr "Janus videorom" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "JavaScript lisensinformasjon" @@ -3151,7 +3131,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Nettpratklient" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3166,7 +3146,7 @@ msgstr "" "ved at det selv bekrefter eierskapet til et domene overfor " "sertifiseringsinstansen (CA) Let's Encrypt." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3178,15 +3158,15 @@ msgstr "" "les og aksepter Let's " "Encrypt Subscriber Agreement før tjenesten brukes." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Sertifikater" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3251,7 +3231,7 @@ msgstr "" "Ingen domener er satt opp. Sett opp domener " "for å kunne skaffe sertifikater for dem." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3260,34 +3240,34 @@ msgstr "" "Sertifikat tilbakekalt for domenet {domain}. Det kan ta en liten stund før " "dette tar effekt." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Klarte ikke å inndra sertifikatet for domenet {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Sertifikat vellykket innhentet til domene {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Klarte ikke å oppnå sertifikat til domene {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Vellykket sletting av sertifikatet for domenet {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Klarte ikke å slette sertifikatet for domenet {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3303,14 +3283,14 @@ msgstr "" "enheter, og krever ikke telefonnumre for å virke. Brukere på en gitt Matrix-" "tjener kan snakke med brukere på alle andre samvirkende Matrix-tjenere." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3412,7 +3392,7 @@ msgstr "" "Matrix Synapse-instanser krever et gyldig TLS-sertifikat. Gå til Let's Encrypt for å skaffe deg det." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3425,7 +3405,7 @@ msgstr "" "lignende nettside, ta noteter, eller samarbeide med andre venner på " "prosjekter." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3439,7 +3419,7 @@ msgstr "" "brukerkontoer fra MediaWiki, ved å gå til Special:CreateAccount-siden." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3447,12 +3427,12 @@ msgstr "" "Alle med en lenke til denne wiki-en kan lese den. Kun innloggede brukere kan " "endre innholdet." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3535,35 +3515,35 @@ msgstr "Passord oppdatert" msgid "Password update failed. Please choose a stronger password" msgstr "Passordoppdatering feilet. Vennligst bruk ett sterkere passord" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Offentlig registrering aktivert" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Offentlig registrering avskrudd" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Privat modus påskrudd" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Privat modus avskrudd" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Forvalgt drakt endret" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Domenenavn oppdatert" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Stedsnavn oppdatert" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, fuzzy, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3576,11 +3556,11 @@ msgstr "" "porten (30000). For å koble til tjeneren trengs en Minetest-klient." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Block-sandkassen" @@ -3630,7 +3610,7 @@ msgstr "" msgid "Address" msgstr "Adresse" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3836,7 +3816,7 @@ msgstr "Secure Shell (SSH)" msgid "Services" msgstr "Tjeneste" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3844,7 +3824,7 @@ msgstr "" "Sett opp nettverksenheter. Sett opp Internett via Ethernet, Wi-Fi eller " "PPPoE. Del den tilkoblingen med andre enheter på nettverket." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3852,7 +3832,7 @@ msgstr "" "Enheter administrert gjennom andre metoder kan være utilgjengelige for " "oppsett her." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Nettverk" @@ -4235,7 +4215,7 @@ msgstr "Rediger tilkobling" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Rediger" @@ -4340,7 +4320,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Metode" @@ -4356,7 +4336,7 @@ msgstr "DNS-tjener" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Forvalg" @@ -4369,7 +4349,7 @@ msgid "This connection is not active." msgstr "Denne forbindelsen er ikke aktiv." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Sikkerhet" @@ -4978,7 +4958,7 @@ msgstr "Tilkobling {name} slettet." msgid "Failed to delete connection: Connection not found." msgstr "Kunne ikke slette tilkobling: Tilkobling ikke funnet." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4995,22 +4975,22 @@ msgstr "" "Du kan også få tilgang til resten av Internettet via {box_name} med utvidet " "sikkerhet og anonymitet." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection Type" msgid "Connect to VPN services" msgstr "Oppkoblingstype" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Virtuelt privat nettverk" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5021,50 +5001,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -#, fuzzy -#| msgid "Moderate" -msgid "Migrate" -msgstr "Moderat" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "For å koble til %(box_name)s VPN må du laste ned en profil og legge den til " @@ -5072,18 +5023,19 @@ msgstr "" "er tilgjengelig for de fleste plattformer. Klikk «Lær mer …» ovenfor, for " "anbefalte klienter, og instruksjoner om hvordan de settes opp." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Profilen er spesifikk for hver enkelt bruker av %(box_name)s. Hold den " "hemmelig." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Last ned min profil" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5096,17 +5048,17 @@ msgstr "" "{box_name}-tjenester ikke nås fra resten av nettet. Dette omfatter de " "følgende situasjoner:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} er bak en begrensende brannmur." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "{box_name} er koblet til en (trådløs) ruter du ikke kan kontrollere." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5114,7 +5066,7 @@ msgstr "" "Din Internett-leverandør gir deg ikke en ekstern IP-adresse, og gir i stedet " "en NAT-et Internett-tilkobling." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5122,11 +5074,11 @@ msgstr "" "Internett-leverandøren gir deg ikke en statisk IP-adresse, og IP-adressen " "endres hver gang du kobler deg til Internett." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Din Internett-leverandør begrenser innkommende oppkoblinger." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, fuzzy, python-brace-format #| msgid "" #| "PageKite works around NAT, firewalls and IP-address limitations by using " @@ -5146,23 +5098,23 @@ msgstr "" "\"https://pagekite.net\">pagekite.net. I fremtiden kan det bli mulig å " "bruke kameratens {box_name} til dette." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Offentlig synlighet" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite-domene" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Tjenerdomene" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5170,31 +5122,31 @@ msgstr "" "Velg din PageKite-tjener. Sett «pagekite.net» for å bruke den forvalgte " "pagekite.net-tjeneren." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Tjenerport" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Port for din PageKite-tjener (default: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "«Kite»-navn" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Eksempel: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Ugyldig «kite»-navn" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "«Kite»-hemmelig" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5202,27 +5154,27 @@ msgstr "" "En hemmelighet knyttet til «Kite»-en, eller den forvalgte hemmeligheten for " "din konto hvis ingen hemmelighet er satt for «Kite»-en." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protokoll" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "Ekstern (frontend) port" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "intern (FreedomBox) port" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Tillat underdomener (Subdomains)" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Deaktivert selvvalgt (tilpasset) tjeneste" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 #, fuzzy #| msgid "" #| "This service is available as a standard service. Please use the " @@ -5232,11 +5184,11 @@ msgstr "" "Denne tjenesten er tilgjengelig som en standard tjeneste. Vennligst bruk " "«Standard Services»-siden for å aktivere den." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Lagt til selvvalgt tjeneste" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Denne tjenesten finnes allerede" @@ -5277,31 +5229,31 @@ msgstr "" "alle protokoll-/portkombinasjoner som du kan definere her. For eksempel, " "HTTPS på andre ting enn 443 er kjent for å forårsake problemer." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Web-tjener (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" "Nettstedet vil være tilgjengelig på http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Web-tjener (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" "Nettstedet vil bli tilgjengelig på https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5347,8 +5299,8 @@ msgstr "" "En annen installasjon eller oppgradering kjører allerede. Vent litt før du " "prøver igjen." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Omstart" @@ -5400,6 +5352,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Slå av nå" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5446,7 +5431,7 @@ msgstr "Mellomtjener for nettet" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Tilgang {url} med mellomtjener {proxy} på tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5463,7 +5448,7 @@ msgstr "" "skrivebordet kan en eller flere Quassel-klienter brukes til å koble til og " "fra." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your desktop , og mobile enheter er tilgjengelig." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC-klient" @@ -5487,7 +5472,7 @@ msgstr "IRC-klient" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5506,7 +5491,7 @@ msgstr "" "href=\"http://radicale.org/clients/\">støttet klientprogram . Radicale " "kan nås av alle brukere med {box_name}-innlogging." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5516,12 +5501,12 @@ msgstr "" "kalendre og adressebøker. Den tilbyr ikke å legge inn nye hendelser eller " "kontakter, det må gjøres med en egen klient." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Kalender og adressebok" @@ -5597,7 +5582,7 @@ msgstr "" "freedombox.adresse>) og ditt brukernavn. Å klikke på søkeknappen vil " "liste opp eksisterende kalendre og adressebøker." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Tilgangskontrolloppsett oppdatert" @@ -5669,8 +5654,8 @@ msgid "" "When enabled, RSS-Bridge can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"Når RSS-Bridge er aktiv er den tilgjengelig for enhver bruker som er medlem av gruppen feed-reader." +"Når RSS-Bridge er aktiv er den tilgjengelig for enhver bruker som er medlem av gruppen feed-reader." #: plinth/modules/rssbridge/__init__.py:27 #, python-brace-format @@ -5680,7 +5665,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Les og abonner på nyhetsstrømmer" @@ -5695,13 +5680,13 @@ msgstr "Bro" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5710,31 +5695,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Tilgang til private delinger" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 #, fuzzy #| msgid "Distributed File Storage" msgid "Network File Storage" @@ -5823,15 +5808,15 @@ msgstr "Delingsnavn" msgid "Action" msgstr "Handlinge" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS disk" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Åpne deling" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 #, fuzzy #| msgid "Add Share" msgid "Group Share" @@ -5865,7 +5850,7 @@ msgstr "Deling redigert." msgid "Error disabling share: {error_message}" msgstr "Feil ved utløsing av enhet: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5873,7 +5858,7 @@ msgstr "" "Searx er en metasøkemotor for Internett som tar hensyn til personvernet. Den " "henter og viser resultater fra flere søkemotorer." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5881,41 +5866,41 @@ msgstr "" "Searx kan brukes for å unngå sporing og profilbygging av søkemotorer. Den " "lagrer ingen kaker som forvalg." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Søk på nettet" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Nettsøk" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Trygt søk" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Velg hvilket forvalgt familiefilter som skal anvendes for dine " "søkeresultater." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Moderat" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Streng" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Tillat offentlig tilgang" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "Tillat dette programmet brukt av alle som kan nå det." @@ -6100,7 +6085,7 @@ msgstr "Bokmerker" msgid "Shaarlier" msgstr "Shaarli" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6110,7 +6095,7 @@ msgstr "" "beskytte din internettrafikk. Den kan brukes til å omgå internettfiltrering " "og -sensur." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6123,7 +6108,7 @@ msgstr "" "enheter kan koble til denne mellomtjeneren, og deres data vil krypteres og " "sendes via Shadowsocks-tjeneren." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6131,40 +6116,40 @@ msgstr "" "For å bruke Shadowsocks etter oppsett, legg SOCKS5-mellomtjenernettadresen " "på din enhet, nettleser, eller program til http://freedombox_address:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "SOCKS5-mellomtjener" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Anbefalt" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Tjener" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Tjernens vertsnavn eller IP-adresse" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Tjener-portnummer" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "Passord brukt for å kryptere data. Må samsvare med tjenerpassord." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Krypteringsmetode. Må samsvare med den brukt på tjeneren." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6173,15 +6158,15 @@ msgstr "" "Deling lar deg dele filer og mapper på din {box_name} over nettet, med en " "utvalgt gruppe brukere." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Deling" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Navn på delt område" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6189,27 +6174,27 @@ msgstr "" "En alfanumerisk streng med små bokstaver som unikt identifiserer en deling. " "Eksempel media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Sti å dele" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Disksti til en mappe på denne tjeneren som du ønsker å dele." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Del offentlig" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Gjør filene i denne mappen tilgjengelig for alle som har lenken." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Brukergrupper som kan lese filene på det delte området:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6217,11 +6202,11 @@ msgstr "" "Brukere i de utvalgte brukergruppene vil også kunne lese filene i det delte " "området." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "En deling ved dette navnet finnes allerede." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "Delte områder bør enten være offentlig eller delt med minst en gruppe" @@ -6258,19 +6243,19 @@ msgstr "Deling lagt til." msgid "Add Share" msgstr "Legg til deling" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Deling redigert." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Rediger deling" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Deling slettet." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6281,7 +6266,7 @@ msgstr "" "tidligere kjent god tilstand i tilfelle det har skjedd uønskede endringer på " "systemet." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6292,7 +6277,7 @@ msgstr "" "etter programvareinstallasjon. Eldre øyeblikksbilder renskes automatisk i " "henhold til innstillingene nedenfor." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for sikkerhetskopier i og med at de er lagret på samme partisjon. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Lagrings-avbildninger" @@ -6409,7 +6394,7 @@ msgstr "Dato" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Slett avbildninger" @@ -6468,57 +6453,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Rull tilbake til øyeblikksbilde #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "manuelt opprettet" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "tidslinje" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Behandle avbildninger" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Opprett øyeblikksbilde." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Oppsett for lagringsavbildninger oppdatert" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Handlingsfeil: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Slettet alle valgte avbildninger" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Øyeblikksbilde i bruk. Prøv igjen senere." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Rullet tilbake til øyeblikksbilde #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Systemet må startes på nytt for å fullføre tilbakerullingen." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Rull tilbake til øyeblikksbilde" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6530,7 +6515,7 @@ msgstr "" "annensteds hen kan utføre administrasjonsoppgaver, kopiere filer eller kjøre " "andre tjenester ved bruk av slike tilkoblinger." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Secure Shell (SSH) tjener" @@ -6573,14 +6558,6 @@ msgstr "Algoritme" msgid "Fingerprint" msgstr "SSH Fingeravtrykk" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "SSH-identitetsbekreftelse med passord avskrudd." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "SSH-autentisering med passord aktivert." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Engangspålogging" @@ -6595,7 +6572,7 @@ msgstr "Login" msgid "Logged out successfully." msgstr "Vellykket passordbytte." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6606,92 +6583,92 @@ msgstr "" "kan vise lagringsmedia som er i bruk, montere og avmontere flyttbare medium, " "utvide rotpartisjonen, osv." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Lager" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} byte" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Operasjonen mislyktes." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Operasjonen ble avbrutt." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Enheten avmonteres allerede." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" "Denne aktiviteten støttes ikke på grunn av manglende driver-/verktøystøtte." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Tidsavbrudd for operasjon." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "Operasjonen vil vekke en disk fra en tilstand av dyp søvn." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Prøver å avmontere en opptatt enhet." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Operasjonen har allerede blitt avbrutt." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Mangler rettigheter til utførelse av forespurt operasjon." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Denne enheten er allerede montert." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Enheten er ikke montert." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Mangler rettigheter til bruk av forespurt valg." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Enheten er montert av en annen bruker." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, fuzzy, no-python-format, python-brace-format #| msgid "" #| "Warning: Low space on system partition ({percent_used}% used, " @@ -6701,15 +6678,15 @@ msgstr "" "Advarsel: Lite plass igjen på systempartisjon ({percent_used}% brukt, " "{free_space} ledig)." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Lite ledig diskplass" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Diskfeil nært forestående" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6718,39 +6695,39 @@ msgstr "" "Disk {id} rapporterer at den sannsynligvis vil feile i nær fremtid. Kopier " "all data mens det fremdeles er mulig og bytt ut disken." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Ugyldig katalognavn." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Mappen finnes ikke." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Stien er ikke en katalog." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Katalogen er ikke leselig for brukeren." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Mappen kan ikke skrives til av brukeren." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Katalog" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Undermappe (valgfritt)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Del" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Annen mappe (angi nedenfor)" @@ -6787,7 +6764,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Utvid root-partisjon" @@ -6808,30 +6785,30 @@ msgstr "" "operasjonen vil det være %(expandable_root_size)s med ekstra plass " "tilgjengelig på root-partisjonen din." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Utviding av partisjon feilet: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Vellykket partisjonsutvidelse." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} kan trygt kobles fra." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Enheten kan trygt kobles fra." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Feil ved utløsing av enhet: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6842,7 +6819,7 @@ msgstr "" "Oppretting, endring og sletting av filer på én enhet vil automatisk bli " "replikert (gjenskapt) til andre enheter." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, fuzzy, python-brace-format #| msgid "" #| "Running Syncthing on {box_name} provides an extra synchronization point " @@ -6867,20 +6844,20 @@ msgstr "" "med sine egne sett med mapper. Webgrensesnittet er bare tilgjengelig for " "brukere som hører til i «admin»-gruppen." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Administrer Syncthing-programmet" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Filsynkronisering" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6894,7 +6871,7 @@ msgstr "" "\"https://www.torproject.org/download/download-easy.html.en\">Tor Browser." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6903,40 +6880,40 @@ msgstr "" "En Tor SOCKS-port er tilgjengelig på din {box_name} for interne nettverk på " "TCP port 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor-løktjeneste" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor Socks-mellomtjener" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor bro-stafettvideresendingsoppsett" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor relay-port tilgjengelig" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3-transport registrert" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4-transport registrert" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Adgang til URL {url} på tcp{kind} via Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bekreft Tor-bruk på {url} via tcp{kind}" @@ -7054,11 +7031,11 @@ msgstr "Løktjeneste" msgid "Ports" msgstr "Porter" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Oppdaterer oppsett" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -7118,7 +7095,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7128,7 +7105,7 @@ msgstr "" "designet for å kunne lese nyheter fra hvor som helst, mens man er så nær en " "virkelig skrivebordsenhet som mulig." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7137,7 +7114,7 @@ msgstr "" "Når aktiv er Tiny Tiny RSS tilgjengelig for enhver " "bruker som er medlem av gruppen feed-reader." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 #, fuzzy #| msgid "" #| "When using a mobile or desktop application for Tiny Tiny RSS, use the URL " @@ -7149,11 +7126,11 @@ msgstr "" "Når du bruker et mobilbasert- eller skrivebords-program for Tiny Tiny RSS, " "bruk nettadressen /tt-rss-appfor å koble til." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Nyhetstrøm-leser" @@ -7161,12 +7138,12 @@ msgstr "Nyhetstrøm-leser" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (avgreining)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "Sjekk og legg til siste programvare- og sikkerhetsoppdateringer." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7174,35 +7151,35 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Programvare-oppdatering" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox oppdatert" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution update started" msgstr "Automatiske oppgraderinger avslått (deaktivert)" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7387,49 +7364,49 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Automatiske oppgraderinger aktivert" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" "Feil ved oppsett av uoppdaterte oppgraderinger (unattended-upgrades): {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Automatiske oppgraderinger aktivert" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Automatiske oppgraderinger avslått (deaktivert)" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 #, fuzzy #| msgid "Automatic upgrades enabled" msgid "Distribution upgrade enabled" msgstr "Automatiske oppgraderinger aktivert" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "Automatic upgrades disabled" msgid "Distribution upgrade disabled" msgstr "Automatiske oppgraderinger avslått (deaktivert)" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Oppgraderingsprosessen (upgrade process) har startet." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Å starte oppgradering (upgrade) mislyktes." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Starter test av distribusjonsoppgradering." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7440,7 +7417,7 @@ msgstr "" "kan kreve at en brukerkonto er medlem av en gruppe for å gi brukeren tilgang " "til programmet." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7451,15 +7428,15 @@ msgstr "" "liste over programmer som er relevante for dem på hjemmesiden. Dog kan kun " "brukere av admin-gruppen endre programmer eller systeminnstillinger." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Brukere og grupper" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Tilgang til alle tjenester og systeminnstillinger" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Sjekk LDAP-oppføring «{search_item}»" @@ -7478,21 +7455,21 @@ msgid "" msgstr "" "Påkrevd. 150 tegn eller mindre. Kun engelske bokstaver, tall og @/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Tilgangspassord" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "Skriv inn passordet for bruker «{user}» for å tillate kontoendringer." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Ugyldig passord." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7506,12 +7483,12 @@ msgstr "" "gruppen kan logge seg på alle tjenester. De kan også logge inn på systemet " "via SSH, og ha administrative rettigheter (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Oppretting av LDAP-bruker mislyktes: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Klarte ikke å legge ny bruker til i {group}-gruppen: {error}" @@ -7530,43 +7507,43 @@ msgstr "" "på systemet uten å bruke passord. Du kan legge inn multiple (flere) nøkler, " "én på hver linje. Blanke linjer og linjer som starter med # vil bli ignorert." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Klarte ikke å bytte navn på LDAP-bruker." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Klarte ikke å slette bruker fra gruppe." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Klarte ikke legge bruker til gruppe." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Klarte ikke sette SSH-nøkler." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "Klarte ikke legge bruker til gruppe." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Klarte ikke å bytte passord for LDAP-bruker." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Klarte ikke å legge til en ny bruker i admin-gruppen: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Klarte ikke å begrense konsolltilgang: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Brukerkonto er opprettet, du er nå logget inn" @@ -7583,12 +7560,12 @@ msgstr "Lagre passord" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Opprett bruker" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Slett bruker" @@ -7629,17 +7606,17 @@ msgid "The following administrator accounts exist in the system." msgstr "Følgende administratorkontoer finnes i systemet." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Brukere" @@ -7672,34 +7649,34 @@ msgstr "" msgid "Save Changes" msgstr "Lagre endringer" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Bruker %(username)s opprettet." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Oppdaterte bruker %(username)s." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Rediger bruker" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Bruker {user} slettet." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Klarte ikke slette LDAP-bruker." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Endre passord" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Vellykket passordbytte." @@ -8060,7 +8037,7 @@ msgstr "Slett tilkobling" msgid "Server deleted." msgstr "Tjener slettet." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8069,7 +8046,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8078,28 +8055,28 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 #, fuzzy #| msgid "Address" msgid "WordPress" msgstr "Adresse" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Wiki and Blog" msgid "Website and Blog" @@ -8118,7 +8095,7 @@ msgstr "" "nettstedet eller bloggen. Aktiver kun etter at oppsettet av Wordpress er " "gjennomført." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8131,7 +8108,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8139,11 +8116,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Organiserer fotografier" @@ -8197,112 +8174,106 @@ msgstr "" msgid "Finished: {name}" msgstr "Tjeneste deaktivert: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Pakke {expression} er ikke tilgjengelig for installasjon" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Pakke {package_name} er siste versjon ({latest_version})" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "Feil under sikkerhetskopiering" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "installering" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "laster ned" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "mediaendring" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "oppsettsfil: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Installer App-er" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Oppdaterer program" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Feil ved programinstallering: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Feil ved programinstallering: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Feil ved programinstallering: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Feil ved programinstallering: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Program installert." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Program oppdatert" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Installer App-er" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Feil ved programinstallering: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Feil ved programinstallering: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Program installert." -#: plinth/setup.py:451 +#: plinth/setup.py:452 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8364,53 +8335,54 @@ msgstr "Installasjon" msgid "Service %(service_name)s is not running." msgstr "Tjenesten %(service_name)s kjører ikke." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Kjernefunksjonalitet og nettbrukergrensesnitt for %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Hjem" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Hjem" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Programmer" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Apps/Programmer" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " System" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "System" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Endre passord" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Slå av" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Logg ut" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Velg språk" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Logg inn" @@ -8699,6 +8671,45 @@ msgstr "før avinstallering av {app_id}" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Aktiver DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Aktiver domenenavnsystemets sikkerhetsutvidelser" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Brannmur-bakgrunnsprosessen kjører ikke. Den må kjøre. Brannmuren kommer " +#~ "som standard aktivert på %(box_name)s. På et Debian-basert system (slik " +#~ "som %(box_name)s), kan du kjøre den med kommandoen «service firewalld " +#~ "start», eller alternativt i et system med systemd, «systemctl start " +#~ "firewalld»." + +#, fuzzy +#~| msgid "Moderate" +#~ msgid "Migrate" +#~ msgstr "Moderat" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "SSH-identitetsbekreftelse med passord avskrudd." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "SSH-autentisering med passord aktivert." + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "Feil under sikkerhetskopiering" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Kjernefunksjonalitet og nettbrukergrensesnitt for %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Nettverksoppkoblinger" diff --git a/plinth/locale/nl/LC_MESSAGES/django.po b/plinth/locale/nl/LC_MESSAGES/django.po index e6cf7a9c5..a149d7841 100644 --- a/plinth/locale/nl/LC_MESSAGES/django.po +++ b/plinth/locale/nl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Dutch calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1051,23 +1044,23 @@ msgstr "" "tot deze toepassing. Alle gebruikers met toegang kunnen alle bibliotheken " "gebruiken." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Gebruik calibre e-book bibliotheken" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "E-boek bibliotheek" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Naam van de nieuwe bibliotheek" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1075,7 +1068,7 @@ msgstr "" "Alleen letters van het Engelse alfabet, cijfers en de tekens _ . en - zonder " "spaties of speciale tekens. Voorbeeld: Mijn_Bibliotheek_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Er bestaat al een bibliotheek met deze naam." @@ -1123,20 +1116,20 @@ msgstr "Ga naar bibliotheek %(library)s" msgid "Delete library %(library)s" msgstr "Verwijder bibliotheek %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Bibliotheek aangemaakt." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Er is een fout opgetreden tijdens het aanmaken van de bibliotheek." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} verwijderd." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Verwijderen van {name} mislukt: {error}" @@ -1184,7 +1177,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Serverbeheer" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1192,18 +1185,18 @@ msgstr "" "Hier kunnen een aantal algemene configuratieopties worden ingesteld, zoals " "hostname, domeinnaam, startpagina etc." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Algemene Instellingen" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Configureer" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1318,48 +1311,48 @@ msgstr "" "Logboeken bevatten informatie over wie toegang heeft gehad tot het systeem " "en foutopsporingsinformatie van verschillende services" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Hostnaam instellen mislukt: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Hostnaam ingesteld" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Domeinnaam instellen mislukt: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Domeinnaam ingesteld" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" "Fout bij het instellen van de startpagina van de webserver: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Startpagina van webserver ingesteld" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Fout bij het wijzigen van de geavanceerde modus: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Geavanceerde toepassingen en functies worden weergeven" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Geavanceerde toepassingen en functies verbergen" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1372,7 +1365,7 @@ msgstr "" "gesprek tot stand te brengen tussen partijen die anders geen verbinding met " "elkaar kunnen maken." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse of ejabberdmoeten worden geconfigureerd met de hier verstrekte details." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP helper" @@ -1444,11 +1437,11 @@ msgstr "Fout bij tijdzone instellen: {exception}" msgid "Time zone set" msgstr "Tijdzone ingesteld" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge is een BitTorrent Cliënt met web-bediening." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1456,16 +1449,16 @@ msgstr "" "Het standaardwachtwoord is 'deluge', maar dit moet zo snel mogelijk na " "activering gewijzigd worden." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Download bestanden met BitTorrent toepassingen" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent-webclient" @@ -1592,7 +1585,7 @@ msgstr "Resultaat" msgid "Diagnostic Test" msgstr "Diagnostische test" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1604,7 +1597,7 @@ msgstr "" "internet. Daardoor is het gebruik van de diensten van {box_name} vaak " "onmogelijk van buiten het lokale netwerk." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1622,7 +1615,7 @@ msgstr "" "naamswijziging doorvoeren, en als iemand op het internet om deze DNS naam " "vraagt wordt dit beantwoord met het juiste IP adres." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1635,11 +1628,11 @@ msgstr "" "diensten van freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Dynamic DNS Cliënt" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Dynamische domeinnaam" @@ -1768,7 +1761,7 @@ msgstr "Dit veld is vereist." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1823,7 +1816,7 @@ msgstr "Server weigert verbinding" msgid "Already up-to-date" msgstr "Al bijgewerkt" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1831,7 +1824,7 @@ msgstr "" "XMPP is een open en gestandaardiseerd communicatie protocol. Hiermee kan een " "XMPP server met de naam ejabberd worden ingesteld." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientgebruiker van {box_name} daartoe " "toegang krijgen." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn toepassing of configureer " "een externe server." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Chatserver" @@ -1983,7 +1976,7 @@ msgstr "" "eruit als username@%(domainname)s. Het domein kan worden ingesteld op " "de Instellingen pagina." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1993,7 +1986,7 @@ msgstr "" "Rspamd. Postfix verstuurt en ontvangt e-mails. Met Dovecot hebben e-" "mailclients toegang tot uw mailbox via IMAP en POP3. Rspamd filtert op spam." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2005,7 +1998,7 @@ msgstr "" "uitgaande e-mail. Sommige heffen de restrictie op na een expliciet verzoek. " "Zie de handleiding pagina voor meer informatie." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2020,7 +2013,7 @@ msgstr "" "adres. Noodzakelijke aliassen zoals \"postmaster\" worden automatisch " "aangemaakt en wijzen naar de eerste admin gebruiker." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2028,7 +2021,7 @@ msgstr "" "Roundcube app biedt gebruikers een " "webinterface om toegang te krijgen tot e-mail." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2159,7 +2152,7 @@ msgstr "Poort" msgid "Host/Target/Value" msgstr "Host/Target/Value" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2170,7 +2163,7 @@ msgstr "" "datastromen van {box_name} stuurt. Een geactiveerde en goed ingestelde " "firewall vermindert het risico op beveiligingsrisico's vanuit internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall" @@ -2190,52 +2183,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Poort {name} ({details}) is niet beschikbaar voor externe netwerken" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Firewall daemon draait niet.De firewall staat standaard aan op %(box_name)s. " -"Op ieder Debian gebaseerd systeem (zoals %(box_name)s) kan het gestart " -"worden door middel van het commando 'service firewalld start' of in het " -"geval van een systeem met systemd 'systemctl start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Dienst/Poort" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Ingeschakeld" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Uitgeschakeld" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Toegestaan" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Toegestaan (alleen intern)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Toegestaan (alleen extern)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Geblokkeerd" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2245,13 +2225,13 @@ msgstr "" "wordt deze ook toegevoegd aan de firewall, en als een dienst wordt " "uitgeschakeld, gebeurt dit ook in de firewall." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Gevorderd" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2304,7 +2284,7 @@ msgstr "Setup starten" msgid "Setup Complete" msgstr "Instelling voltooid" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2323,7 +2303,7 @@ msgstr "" "line als grafische versies beschikbaar). En je kan je broncode delen met " "mensen over de hele wereld." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2331,71 +2311,71 @@ msgstr "" "Bezoek Git tutorial " "voor meer informatie over het gebruik van Git." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Lees- en schrijftoegang tot Git-repositories" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Eenvoudige Git Hosting" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Ongeldige repository URL." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Ongeldige repository naam." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Naam van een nieuwe repository of URL om een bestaande repository te " "importeren." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Beschrijving van de repository" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Optioneel, voor weergave op Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Naam eigenaar repository" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Privérepository" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Geef alleen geautoriseerde gebruikers toegang tot deze repository." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Er bestaat al een repository met deze naam." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Naam van de repository" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" "Een alfanumerieke tekenreeks die op unieke wijze een repository " "identificeert." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Standaard versie" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb geeft dit weer als een standaard branch." @@ -2439,19 +2419,19 @@ msgstr "Verwijder Git Repository %(name)s" msgid "Delete this repository permanently?" msgstr "Deze repository permanent verwijderen?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Repository aangemaakt." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Er is een fout opgetreden bij het aanmaken van de repository." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Repository gewijzigd." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Wijzig repository" @@ -2819,7 +2799,7 @@ msgstr "Over {box_name}" msgid "{box_name} Manual" msgstr "{box_name} Handleiding" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2831,7 +2811,7 @@ msgstr "" "voor anonimiteit door gecodeerd verkeer te sturen via een netwerk dat door " "vrijwilligers over de hele wereld wordt verspreid." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2839,7 +2819,7 @@ msgstr "" "Vind meer informatie over I2P op hun project homepage." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2847,19 +2827,19 @@ msgstr "" "Bij het eerste bezoek aan de meegeleverde webinterface wordt het " "configuratieproces gestart." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "I2P-toepassing beheren" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Anonimiteitsnetwerk" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P proxy" @@ -2905,7 +2885,7 @@ msgstr "" "peer netwerk. Download bestanden door torrents toe te voegen of maak een " "nieuwe torrent om een bestand te delen." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2915,7 +2895,7 @@ msgstr "" "verschillende lichtgewicht markup-talen, met inbegrip van Markdown, en " "algemene blogging functionaliteit zoals reacties en RSS-feeds." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2929,15 +2909,15 @@ msgstr "" "Configuratie kan je deze instellingen wijzigen en nieuwe gebruikers " "registreren." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki en Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Bekijken en bewerken van wiki toepassingen" @@ -2993,43 +2973,43 @@ msgstr "" "Deze actie zal alle bijdragen, pagina's, en commentaar inclusief revisie-" "historie. Deze wiki of blog permanent verwijderen?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Wiki {name} gemaakt." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Kan wiki niet aanmaken: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Blog {name} gemaakt." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Kan blog niet aanmaken: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} verwijderd." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Verwijderen van {title} mislukt: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" "infinoted is een server voor Gobby, een tekst-editor voor gezamenlijk " "gebruik." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3040,11 +3020,11 @@ msgstr "" "a> desktop-client en installeer deze. Start Gobby en selecteer vervolgens " "\"Verbinden met Server\" en voer de {box_name} domeinnaam in." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby Server" @@ -3092,7 +3072,7 @@ msgstr "Janus Video Ruimte" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "JavaScript licentie-informatie" @@ -3112,7 +3092,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Chat Cliënt" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3128,7 +3108,7 @@ msgstr "" "van een domein te zijn tegenover Let's Encrypt, een certificaatwaarmerker " "(CA)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3141,15 +3121,15 @@ msgstr "" "\"https://letsencrypt.org/repository/\">Let's Encrypt Subscriber Agreement vóór het gebruik van deze dienst." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Certificaten" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Kan niet testen: Er zijn geen domeinen ingesteld." @@ -3214,7 +3194,7 @@ msgstr "" "Er zijn geen geconfigureerde domeinen. Stel " "domeinen in om certificaten ervoor te kunnen uitgeven." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3223,34 +3203,34 @@ msgstr "" "Certificaat met succes ingetrokken voor domein {domain}. Het kan enige tijd " "duren voordat het effect heeft." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Intrekken certificaat voor domein {domain} mislukt: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Certificaat voor domein {domain} met succes verkregen" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Verkrijgen van certificaat voor domein {domain} is mislukt: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Certificaat met succes verwijderd voor domein {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Verwijderen certificaat voor domein {domain} mislukt: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3267,7 +3247,7 @@ msgstr "" "Matrix server kunnen gesprekken aangaan met gebruikers op alle andere Matrix " "servers door federatie (gedecentraliseerd netwerk)." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3277,7 +3257,7 @@ msgstr "" "videogesprekken. Installeer de Coturn " "toepassing of configureer een externe server." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3385,7 +3365,7 @@ msgstr "" "vereist. Ga naar Let's Encrypt om er een " "te verkrijgen." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3398,7 +3378,7 @@ msgstr "" "gebruiken om een wiki website aan te bieden, persoonlijke aantekeningen bij " "te houden of met vrienden aan een gezamenlijke website te werken." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3412,7 +3392,7 @@ msgstr "" "vanuit MediaWiki op de Speciaal:GebruikerRegistreren pagina." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3420,12 +3400,12 @@ msgstr "" "Iedereen met een link naar deze wiki kan hem lezen. Alleen ingelogde " "gebruikers kunnen wijzigingen aanbrengen in de inhoud." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3507,35 +3487,35 @@ msgstr "Wachtwoord bijgewerkt" msgid "Password update failed. Please choose a stronger password" msgstr "Wachtwoordupdate mislukt. Kies een sterker wachtwoord" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Openbare registraties ingeschakeld" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Openbare registraties uitgeschakeld" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Privé-modus ingeschakeld" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Privé-modus uitgeschakeld" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Standaard uiterlijk veranderd" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Domeinnaam bijgewerkt" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Sitenaam bijgewerkt" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3548,11 +3528,11 @@ msgstr "" "standaardpoort (30000). Voor de verbinding met de server is een Minetest client nodig." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Block Sandbox" @@ -3604,7 +3584,7 @@ msgstr "Indien uitgeschakeld, kunnen spelers niet sterven of schade oplopen." msgid "Address" msgstr "Adres" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3792,7 +3772,7 @@ msgstr "Secure Shell" msgid "Services" msgstr "Diensten" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3800,7 +3780,7 @@ msgstr "" "Stel netwerkapparaten in. Maak verbinding met internet via Ethernet, Wi-Fi " "of PPPoE. Deel die verbinding met andere apparaten op het netwerk." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3808,7 +3788,7 @@ msgstr "" "Apparaten die via andere methoden worden beheerd, zijn hier mogelijk niet " "beschikbaar voor configuratie." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Netwerken" @@ -4245,7 +4225,7 @@ msgstr "Wijzig verbinding" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Wijzig" @@ -4350,7 +4330,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Methode" @@ -4366,7 +4346,7 @@ msgstr "DNS server" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Standaard" @@ -4379,7 +4359,7 @@ msgid "This connection is not active." msgstr "Deze verbinding is niet actief." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Security" @@ -4965,7 +4945,7 @@ msgstr "Verbinding {name} verwijderd." msgid "Failed to delete connection: Connection not found." msgstr "Kan verbinding niet verwijderen: Verbinding niet gevonden." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4983,20 +4963,20 @@ msgstr "" "mogelijk om de rest van het internetgebruik via {box_name} te leiden, voor " "meer veiligheid en anonimiteit." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Verbinding maken met VPN-dienst" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Virtual Private Network" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5007,58 +4987,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Migreer naar ECC" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Je OpenVPN-installatie gebruikt momenteel RSA. Overschakelen naar de moderne " -"Elliptic Curve Cryptography verbetert de snelheid van het tot stand brengen " -"van een verbinding en de beveiliging. Deze operatie is onomkeerbaar. Dit zou " -"slechts enkele minuten moeten duren op de meeste single board computers." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Alle nieuwe installaties van OpenVPN op %(box_name)s zullen standaard ECC " -"gebruiken. We raden aan om zo snel mogelijkover te stappen." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Waarschuwing: Bestaande clientprofielen worden door deze bewerking " -"ongeldig gemaakt. Alle OpenVPN-gebruikers op %(box_name)s moeten nieuwe " -"profielen downloaden. Om verbinding te maken met deze server moet een " -"OpenVPN-client die compatibel is met ECC worden gebruikt." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Migreren" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profiel" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Om te verbinden met de VPN van %(box_name)s moet een profiel worden " @@ -5067,17 +5010,18 @@ msgstr "" "platformen. Klik op \"Meer info...\" hierboven voor aanbevolen programma's " "en gebruiksinstructies." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Profielen zijn voor iedere gebruiker van %(box_name)s anders. Houd ze geheim." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Download mijn profiel" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5090,19 +5034,19 @@ msgstr "" "vereist als de diensten op {box_name} niet te bereiken zijn vanaf de rest " "van internet. Dit is het geval in de volgende situaties:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} is verbonden achter een beperkende firewall." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} is verbonden met een (wireless) router die niet onder eigen " "controle staat." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5110,7 +5054,7 @@ msgstr "" "De internetprovider geeft geen extern IP adres maar maakt gebruik van een " "NAT verbinding." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5118,11 +5062,11 @@ msgstr "" "De internetprovider geeft geen statisch IP adres, en het IP adres verandert " "telkens wanneer je verbinding maakt met internet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "De internetprovider beperkt inkomende verbindingen." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5136,23 +5080,23 @@ msgstr "" "\">pagekite.net. In de toekomst is het misschien mogelijk om de " "{box_name} van een van je vrienden te gebruiken." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Openbare zichtbaarheid" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite domein" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Serverdomein" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5160,31 +5104,31 @@ msgstr "" "Selecteer een pagekite server. Gebruik \"pagekite.net\" om de standaard " "pagekite.net server te gebruiken." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Serverpoort" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Poort voor de pagekite server (default: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kitenaam" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Voorbeeld: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Foute kite-naam" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite-geheim" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5192,35 +5136,35 @@ msgstr "" "Het wachtwoord dat met deze kite is verbonden, en het standaard wachtwoord " "voor deze account als deze kite geen eigen wachtwoord heeft." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protocol" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "externe (frontend) poort" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "interne (freedombox) poort" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Subdomeinen Inschakelen" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Verwijderde aangepaste dienst" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Deze dienst is al beschikbaar als een standaarddienst." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Aangepaste dienst toevoegen" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Deze dienst bestaat al" @@ -5258,31 +5202,31 @@ msgstr "" "bijvoorbeeld bekend dat HTTPS servers die niet op poort 443 worden ingesteld " "problemen opleveren." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Webserver (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" "De website zal beschikbaar zijn op http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Webserver (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" "De website zal beschikbaar zijn op https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5334,8 +5278,8 @@ msgstr "" "Er wordt nu een installatie of upgrade uitgevoerd. Wacht alstublieft tot dit " "voltooid is voordat je het apparaat herstart of uitzet." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Herstarten" @@ -5385,6 +5329,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Nu Uitschakelen" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5425,7 +5402,7 @@ msgstr "Web Proxy" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Gebruik {url} via proxy {proxy} op tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5443,7 +5420,7 @@ msgstr "" "mobiele telefoon kunnen worden gebruikt om te verbinden of de verbinding te " "verbreken." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your desktop en mobiele apparaten." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC Cliënt" @@ -5467,7 +5444,7 @@ msgstr "IRC Cliënt" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5482,7 +5459,7 @@ msgstr "" "\">ondersteunde clienttoepassing nodig. Radicale kan worden benaderd " "door elke {box_name} gebruiker." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5493,12 +5470,12 @@ msgstr "" "gebeurtenissen of contactpersonen, die moeten worden gedaan met behulp van " "een aparte client." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Agenda en Adresboek" @@ -5572,7 +5549,7 @@ msgstr "" "freedombox.address>) en je gebruikersnaam. Klikken op de zoekknop zal de " "bestaande kalenders en adresboeken weergeven." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Configuratie van de toegangsrechten is bijgewerkt" @@ -5663,7 +5640,7 @@ msgstr "" "verschillende websites te volgen. Schakel bij het toevoegen van een feed " "authenticatie in en gebruik de {box_name}-inloggegevens." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Lezen en abonneren op nieuwsfeeds" @@ -5676,7 +5653,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "RSS Feed Generator" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5684,7 +5661,7 @@ msgstr "" "Met Samba kunnen bestanden en mappen worden gedeeld tussen FreedomBox en " "andere computers in het lokale netwerk." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5698,11 +5675,11 @@ msgstr "" "smb://{hostname}.local (op Linux en Mac). Er zijn drie soorten van delen " "waaruit gekozen kan worden: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Open deelmap - toegankelijk voor iedereen in het lokale netwerk." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5710,7 +5687,7 @@ msgstr "" "Groeps deelmap - alleen toegankelijk voor FreedomBox-gebruikers die deel " "uitmaken van de freedombox-share-groep." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5718,15 +5695,15 @@ msgstr "" "Prive-deelmap - - iedere gebruiker in de freedombox-share-groep kan zijn " "eigen privéruimte hebben." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Toegang tot de privéshares" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Netwerk bestandenopslag" @@ -5815,15 +5792,15 @@ msgstr "Gedeelde map naam" msgid "Action" msgstr "Actie" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS-schijf" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Gedeelde map openen" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Gedeelde map" @@ -5849,7 +5826,7 @@ msgstr "Gedeelde map uitgeschakeld." msgid "Error disabling share: {error_message}" msgstr "Fout bij het uitschakelen van de gedeelde map: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5857,7 +5834,7 @@ msgstr "" "Searx is een privacy-respecterende internet metasearch engine. Het " "aggregeert en toont resultaten van meerdere zoekmachines." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5865,39 +5842,39 @@ msgstr "" "Searx kan worden gebruikt om tracking en profilering door zoekmachines te " "voorkomen. Het slaat standaard geen cookies op." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Zoeken op internet" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Zoeken op het Internet" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Veilig Zoeken" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "Kies het standaard familiefilter om toe te passen op zoekresultaten." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Modereren" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Strikt" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Openbare toegang toestaan" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Sta toe dat deze toepassing wordt gebruikt door iedereen die er toegang toe " @@ -6078,7 +6055,7 @@ msgstr "Bladwijzers" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6088,7 +6065,7 @@ msgstr "" "beschermen. Het kan gebruikt worden om censuur en het filteren van Internet " "te omzeilen." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6101,7 +6078,7 @@ msgstr "" "Apparaten in het lokale netwerk kunnen met deze proxy verbinden, en hun data " "zal versleuteld via de Shadowsocks server verstuurd worden." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6110,42 +6087,42 @@ msgstr "" "proxy in op het apparaat, webbrowser of toepassing naar http://" "adres_van_de_freedombox:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Socks5 Proxy" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Aanbevolen" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Server" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Server hostnaam of IP adres" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Server poortnummer" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Wachtwoord dat wordt gebruikt om gegevens te coderen. Moet overeenkomen met " "serverwachtwoord." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Encryptie methode. Moet overeenkomen met de instelling van de server." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6154,15 +6131,15 @@ msgstr "" "Delen maakt het mogelijk om bestanden en mappen op {box_name} te delen via " "het Internet met door jou bepaalde gebruikers." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Delen" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Naam van de gedeelde bron" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6170,27 +6147,27 @@ msgstr "" "Een aaneengesloten reeks van kleine letters en/of cijfers, die " "bestandsdeling aanduidt. Bijvoorbeeld: media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Te delen pad" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Pad naar een map op deze server die je wilt delen." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Openbare share" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Bestanden in deze map beschikbaar maken voor iedereen met de link." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Gebruikersgroepen die de bestanden in de share kunnen lezen:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6198,11 +6175,11 @@ msgstr "" "Gebruikers in de geselecteerde gebruikersgroepen kunnen de bestanden in de " "share lezen." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Er bestaat reeds een gedeelde map met deze naam." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "Shares moeten openbaar zijn of gedeeld worden met minimaal één groep" @@ -6239,19 +6216,19 @@ msgstr "Gedeelde map toegevoegd." msgid "Add Share" msgstr "Gedeelde map toevoegen" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Gedeelde map bewerkt." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Gedeelde map bewerken" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Gedeelde map verwijderd." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6261,7 +6238,7 @@ msgstr "" "kunnen worden gebruikt om in geval van ongewenste wijzigingen aan het " "systeem terug te keren naar een voorheen goed werkende staat." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6272,7 +6249,7 @@ msgstr "" "voor en na een software-installatie. Oudere Snapshots worden automatisch " "opgeschoond volgens de onderstaande instellingen." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups aangezien ze op dezelfde partitie als hun bron worden " "bewaard. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Opslag Snapshots" @@ -6386,7 +6363,7 @@ msgstr "Datum" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Snapshots verwijderen" @@ -6440,58 +6417,58 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Terugdraaien tot Snapshot #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "handmatig gemaakt" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "tijdlijn" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Beheren van Snapshots" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Gemaakte snapshot." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Opslag van Snapshots configuratie is bijgewerkt" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Actiefout: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Verwijderde geselecteerde snapshots" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Snapshot is momenteel in gebruik. Probeer het later nog eens." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Teruggezet naar snapshot #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" "Het systeem moet opnieuw worden opgestart om het terugdraaien te voltooien." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Terugdraaien naar Snapshot" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6503,7 +6480,7 @@ msgstr "" "andere locatie die daarvoor geautoriseerd is, kan beheerdertaken uitvoeren, " "bestanden kopiëren en andere taken verrichten door zulk een verbinding." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Secure Shell (SSH) Server" @@ -6541,14 +6518,6 @@ msgstr "Algoritme" msgid "Fingerprint" msgstr "Vingerafdruk" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "SSH-authenticatie met wachtwoord uitgeschakeld." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "SSH-authenticatie met wachtwoord ingeschakeld." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Eenmalige aanmelding" @@ -6561,7 +6530,7 @@ msgstr "Aanmelding" msgid "Logged out successfully." msgstr "Succesvol uitgelogd." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6573,109 +6542,109 @@ msgstr "" "bekijken, verwijderbare media koppelen en ontkoppelen, de rootpartitie " "uitbreiden enz." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Storage" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bytes" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "De bewerking is mislukt." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "De bewerking is afgebroken." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Het apparaat is al aan het ontkoppelen." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" "De bewerking wordt niet ondersteund vanwege ontbrekende driver / programma-" "ondersteuning." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Er is een time-out opgetreden voor deze bewerking." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" "De operatie zou een schijf wakker maken die in \"diepe slaap\" stand is." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Poging om een apparaat te ontkoppelen dat in gebruik is." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "De bewerking is al geannuleerd." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Niet gemachtigd om deze handeling uit te voeren." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Het apparaat is al gekoppeld." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Het apparaat is niet ge-mount." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Het is niet toegestaan de gevraagde optie te gebruiken." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Het apparaat is door een andere gebruiker aangekoppeld." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Weinig ruimte op de systeempartitie: {percent_used} % gebruikt, {free_space} " "vrij." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Weinig schijfruimte" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Schijffout dreigt" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6684,39 +6653,39 @@ msgstr "" "Schijf {id} meldt dat het waarschijnlijk in de nabije toekomst defect zal " "zijn. Kopieer alle gegevens terwijl het nog kan en vervang de schijf." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Ongeldige mapnaam." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Map bestaat niet." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Pad is geen map." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Map is niet leesbaar door de gebruiker." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Map is niet schrijfbaar door de gebruiker." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Opslagmap" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Submap (optioneel)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Delen" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Andere map (hieronder aangeven)" @@ -6753,7 +6722,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Root-partitie uitbreiden" @@ -6776,30 +6745,30 @@ msgstr "" "zal %(expandable_root_size)s extra vrije ruimte in de root-partitie " "beschikbaar zijn." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Fout bij partitie uitbreiden: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Partitie succesvol uitgebreid." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} kan veilig worden losgekoppeld." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Het apparaat kan veilig worden losgekoppeld." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Fout bij verwijderen van apparaat: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6812,7 +6781,7 @@ msgstr "" "zullen automatisch dezelfde veranderingen ondergaan op de andere apparaten " "waarop Syncthing draait." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6830,20 +6799,20 @@ msgstr "" "{box_name} is alleen beschikbaar voor gebruikers die tot de \"admin\"- of de " "\"syncthing-access\"-groep behoren." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Beheer Syncthing toepassing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Bestandssynchronisatie" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6857,7 +6826,7 @@ msgstr "" "de Tor " "Browser aan." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6866,40 +6835,40 @@ msgstr "" "Een Tor SOCKS poort is beschikbaar op {box_name} voor interne netwerken op " "TCP poort 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor-Onion Dienst" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor Socks Proxy" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor Bridge Relay" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor relay poort beschikbaar" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 transport geregistreerd" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 transport geregistreerd" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Gebruik URL {url} op tcp{kind} via Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bevestig Tor gebruik met {url} via tcp{kind}" @@ -7022,11 +6991,11 @@ msgstr "Onion Service" msgid "Ports" msgstr "Poorten" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Configuratie bijwerken" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Fout bij het configureren van de toepassing: {error}" @@ -7088,7 +7057,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7098,7 +7067,7 @@ msgstr "" "om het lezen van nieuws vanaf iedere locatie mogelijk te maken, terwijl het " "zoveel mogelijk als een echte desktoptoepassing wil werken." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7107,7 +7076,7 @@ msgstr "" "Indien ingeschakeld, kan Tiny Tiny RSS worden geopend door elke gebruiker die tot de feed-reader groep behoort." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7115,11 +7084,11 @@ msgstr "" "Gebruik de URL /tt-rss-app in om te verbinden " "met een mobiele- of desktoptoepassing voor Tiny Tiny RSS." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "News Feed Reader" @@ -7127,13 +7096,13 @@ msgstr "News Feed Reader" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Controleer de nieuwste software- en beveiligingsupdates en pas deze toe." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7146,22 +7115,22 @@ msgstr "" "het systeem opnieuw moet worden opgestart, gebeurt dit automatisch om 02:00 " "uur, waardoor alle toepassingen even niet beschikbaar zijn." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Software bijwerken" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox geaktualiseerd" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Kan distributie-update niet starten" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7171,11 +7140,11 @@ msgstr "" "te starten. Zorg ervoor dat ten minste 5 GB ruimte vrij is. Als " "ingeschakeld, wordt de distributie-update na 24 uur opnieuw geprobeerd." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Distributie-update gestart" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "Update naar volgende stabiele release gestart. Dit kan lang duren." @@ -7353,44 +7322,44 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Test de distributie-upgrade nu" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Fout bij het instellen van automatische upgrades: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Automatisch bijwerken ingeschakeld" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Automatisch bijwerken uitgeschakeld" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Distributie bijwerken ingeschakeld" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Distributie bijwerken uitgeschakeld" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Upgrade-proces gestart." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Starten van de upgrade is mislukt." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Tussentijdse Software Updates zijn ingeschakeld." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Start de distributie upgrade test." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7401,7 +7370,7 @@ msgstr "" "apps moet een gebruikersaccount deel uitmaken van een groep om de gebruiker " "toegang te geven tot de toepassing." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7413,15 +7382,15 @@ msgstr "" "die lid zijn van de admin -groep mogen toepassings- of " "systeeminstellingen wijzigen." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Gebruikers en Groepen" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Toegang tot alle diensten en systeeminstellingen" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Zoek LDAP item \"{search_item}\"" @@ -7439,11 +7408,11 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "Vereist. 150 tekens of minder. Alleen letters, cijfers en @/./-/_ ." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Authorisatie-wachtwoord" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7451,11 +7420,11 @@ msgstr "" "Voer het wachtwoord voor gebruiker \"{user}\" in om accountwijzigingen toe " "te staan." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Ongeldig wachtwoord." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7470,12 +7439,12 @@ msgstr "" "ook op het systeem inloggen met SSH en kunnen systeemadministratie doen " "(sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "LDAP gebruiker aanmaken mislukt: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Toevoegen van gebruiker aan groep {group} mislukt: {error}" @@ -7495,41 +7464,41 @@ msgstr "" "meerdere sleutels toevoegen, één op elke regel. Lege regels en regels die " "beginnen met # worden genegeerd." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "LDAP gebruiker hernoemen mislukt." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Gebruiker uit groep verwijderen mislukt." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Gebruiker aan groep toevoegen mislukt." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Kan de SSH-sleutels niet instellen." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Gebruikerstatus aanpassen mislukt." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Wijzigen LDAP gebruikerswachtwoord mislukt." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Toevoegen van gebruiker aan admin groep mislukt: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Consoletoegang beperken is mislukt: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Gebruikersaccount aangemaakt, je bent nu ingelogd" @@ -7546,12 +7515,12 @@ msgstr "Wachtwoord Opslaan" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Nieuwe gebruiker registreren" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Gebruiker verwijderen" @@ -7592,13 +7561,19 @@ msgid "The following administrator accounts exist in the system." msgstr "De volgende beheerprofielen bestaan in het systeem." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Verwijder deze accounts door middel van de opdrachtregel en vernieuw de " "pagina om een account aan te maken dat te gebruiken is met %(box_name)s. " @@ -7607,7 +7582,7 @@ msgstr "" "account al bruikbaar is bij %(box_name)s." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Gebruikers" @@ -7640,34 +7615,34 @@ msgstr "" msgid "Save Changes" msgstr "Wijzigingen opslaan" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Gebruiker %(username)s aangemaakt." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Gebruiker %(username)s bijgewerkt." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Gebruiker wijzigen" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Gebruiker {user} verwijderd." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Verwijderen van LDAP gebruiker mislukt." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Wijzig wachtwoord" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Wachtwoord succesvol gewijzigd." @@ -8008,7 +7983,7 @@ msgstr "Verwijder verbinding met server" msgid "Server deleted." msgstr "Server verwijderd." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8022,7 +7997,7 @@ msgstr "" "met thema's. De website en het beheer ervan is bruikbaar met een mobiel " "apparaat." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8035,7 +8010,7 @@ msgstr "" "{box_name} opent met de juiste domeinnaam. Schakel permalinks in de " "beheerdersinterface in voor betere URL's naar uw pagina's en berichten." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8046,7 +8021,7 @@ msgstr "" "\"/wordpress/wp-admin/\">administratie pagina om in de toekomst de " "administratie interface te bereiken." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8056,12 +8031,12 @@ msgstr "" "vanuit de beheerdersinterface. Extra plug-ins of thema's kunnen op eigen " "risico worden geïnstalleerd en geüpgraded." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Website en Blog" @@ -8078,7 +8053,7 @@ msgstr "" "WordPress-site of blog bekijken. Alleen inschakelen na het uitvoeren van de " "eerste WordPress-configuratie." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8100,7 +8075,7 @@ msgstr "" "van zoekwoorden, kaart- en kalenderweergaven. Individuele foto's kunnen met " "anderen worden gedeeld door een directe link te sturen." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8111,11 +8086,11 @@ msgstr "" "Zoph. Voor extra gebruikers moeten zowel in {box_name} als in Zoph accounts " "worden aangemaakt met dezelfde gebruikersnaam." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Foto Organisator" @@ -8169,96 +8144,92 @@ msgstr "Wachten om te starten: {name}" msgid "Finished: {name}" msgstr "Klaar: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Pakket {expression} is niet beschikbaar voor installatie" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Pakket {package_name} is de nieuwste versie ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Fout bij het uitvoeren van apt-get" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "installeren" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "downloaden" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "media wijzigen" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "configuratiebestand: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Time-out wachtend op pakketbeheerder" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Toepassing installeren" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Toepassing updaten" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Fout bij het installeren van de toepassing: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Fout bij het bijwerken van de toepassing: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Fout bij het installeren van de toepassing: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Fout bij het bijwerken van de toepassing: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "De toepassing is geïnstalleerd." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Toepassing bijgewerkt" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Toepassing wordt verwijderd" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Fout bij het verwijderen van de toepassing: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Fout bij het verwijderen van de toepassing: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "De toepassing is verwijderd." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Toepassings-pakketten bijwerken" @@ -8318,53 +8289,54 @@ msgstr "Installatie" msgid "Service %(service_name)s is not running." msgstr "Service %(service_name)s is niet actief." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Basisfunctionaliteit en webinterface voor %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Startpagina" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Startpagina" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Toepassingen" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Toepassingen" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Systeem" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Systeem" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Wijzig wachtwoord" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Uitschakelen" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Afmelden" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Selecteer taal" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Aanmelden" @@ -8653,6 +8625,75 @@ msgstr "voor het verwijderen van {app_id}" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "DNSSEC Inschakelen" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Domeinnaamsysteem beveiliging-extensies inschakelen" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Firewall daemon draait niet.De firewall staat standaard aan op " +#~ "%(box_name)s. Op ieder Debian gebaseerd systeem (zoals %(box_name)s) kan " +#~ "het gestart worden door middel van het commando 'service firewalld start' " +#~ "of in het geval van een systeem met systemd 'systemctl start firewalld'." + +#~ msgid "Migrate to ECC" +#~ msgstr "Migreer naar ECC" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Je OpenVPN-installatie gebruikt momenteel RSA. Overschakelen naar de " +#~ "moderne Elliptic Curve Cryptography verbetert de snelheid van het tot " +#~ "stand brengen van een verbinding en de beveiliging. Deze operatie is " +#~ "onomkeerbaar. Dit zou slechts enkele minuten moeten duren op de meeste " +#~ "single board computers." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Alle nieuwe installaties van OpenVPN op %(box_name)s zullen standaard ECC " +#~ "gebruiken. We raden aan om zo snel mogelijkover te stappen." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Waarschuwing: Bestaande clientprofielen worden door deze bewerking " +#~ "ongeldig gemaakt. Alle OpenVPN-gebruikers op %(box_name)s moeten nieuwe " +#~ "profielen downloaden. Om verbinding te maken met deze server moet een " +#~ "OpenVPN-client die compatibel is met ECC worden gebruikt." + +#~ msgid "Migrate" +#~ msgstr "Migreren" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "SSH-authenticatie met wachtwoord uitgeschakeld." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "SSH-authenticatie met wachtwoord ingeschakeld." + +#~ msgid "Error running apt-get" +#~ msgstr "Fout bij het uitvoeren van apt-get" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Basisfunctionaliteit en webinterface voor %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Netwerkverbindingen" diff --git a/plinth/locale/pl/LC_MESSAGES/django.po b/plinth/locale/pl/LC_MESSAGES/django.po index bc37e252a..dc4f13006 100644 --- a/plinth/locale/pl/LC_MESSAGES/django.po +++ b/plinth/locale/pl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Polish calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Create new repository" msgid "Name of the new library" msgstr "Utwórz nowe repozytorium" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 #, fuzzy #| msgid "Remote backup repository already exists." msgid "A library with this name already exists." @@ -1118,22 +1111,22 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 #, fuzzy #| msgid "Repository removed." msgid "Library created." msgstr "Usunięto repozytorium." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "Usunięto {name}." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1177,7 +1170,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Administracja serwera" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1185,18 +1178,18 @@ msgstr "" "Tutaj możesz ustawić kilka ogólnych opcji konfiguracji, takich jak nazwa " "hosta, nazwa domeny, strona główna serwera www itp." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Ustawienia główne" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Konfiguruj" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1306,47 +1299,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Błąd podczas ustawiania nazwy hosta: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Nazwa hosta ustawiona" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Błąd ustawiania nazwy domeny {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Nazwa domeny ustawiona" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Błąd podczas ustawiania strony domowej serwera web: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Ustawiono stronę domową serwera web" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Błąd podczas zmiany trybu zaawansowanego: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Wyświetlanie zaawansowanych aplikacji i cech" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Ukrywanie zaawansowanych aplikacji i cech" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1354,7 +1347,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as freedns." "afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Klient Dynamic DNS" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Dynamiczna nazwa domeny" @@ -1760,7 +1753,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1825,7 +1818,7 @@ msgstr "" msgid "Already up-to-date" msgstr "Ostatnie uaktualnienie" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1833,7 +1826,7 @@ msgstr "" "XMPP jest otwartym i ustandaryzowanym protokołem komunikacyjnym. Tu możesz " "uruchomić i skonfigurować własny serwer XMPP zwany ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientklienta XMPP. Gdy włączony, ejabberd jest " "dostępny dla każdego użytkownika {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Serwer czatu" @@ -1973,14 +1966,14 @@ msgstr "" "i>. Możesz ustawić swoją domenę na stronie Konfiguruj." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1988,7 +1981,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1998,13 +1991,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2145,7 +2138,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2156,7 +2149,7 @@ msgstr "" "ruch sieciowy na twoim {box_name}. Włączony i poprawnie skonfigurowany " "firewall redukuje ryzyko zagrożeń z Internetu." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall" @@ -2176,52 +2169,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Proces firewalla nie jest uruchomiony. Proszę go włączyć. Firewall jest " -"domyślnie włączony na %(box_name)s. Na każdym systemie bazującym na Debianie " -"(jak %(box_name)s) możesz go włączyć używając komendy 'service firewalld " -"start' lub, w przypadku systemu z systemd 'systemctl start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Usługa/Port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Włączony" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Wyłączony" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Zezwolono" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Zezwolono (tylko wewnętrzne)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Zezwolono (tylko zewnętrzne)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Zablokowano" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2231,13 +2211,13 @@ msgstr "" "automatycznie przepuszczana przez firewall a gdy jest wyłączona, jest " "również blokowana przez firewall." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2285,7 +2265,7 @@ msgstr "Rozpocznij" msgid "Setup Complete" msgstr "Instalacja zakończona" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2296,37 +2276,37 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository URL." msgstr "Niewłaściwa nazwa hosta" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository name." msgstr "Niewłaściwa nazwa hosta" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 #, fuzzy #| msgid "" #| "Repository path is neither empty nor is an existing backups repository." @@ -2334,55 +2314,55 @@ msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Ścieżka repozytorium jest pusta lub nie jest repozytorium kopii zapasowych." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 #, fuzzy #| msgid "Create new repository" msgid "Description of the repository" msgstr "Utwórz nowe repozytorium" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 #, fuzzy #| msgid "Repository removed." msgid "Repository's owner name" msgstr "Usunięto repozytorium." -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Create Repository" msgid "Private repository" msgstr "Utwórz repozytorium" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 #, fuzzy #| msgid "Remote backup repository already exists." msgid "A repository with this name already exists." msgstr "Zdalne repozytorium już istnieje." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Create new repository" msgid "Name of the repository" msgstr "Utwórz nowe repozytorium" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Setting unchanged" msgid "Default branch" msgstr "Ustawienie bez zmian" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2433,23 +2413,23 @@ msgstr "Usuń wiki lub blog %(name)s" msgid "Delete this repository permanently?" msgstr "Usunąć trwale to archiwum?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 #, fuzzy #| msgid "Repository removed." msgid "Repository created." msgstr "Usunięto repozytorium." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 #, fuzzy #| msgid "Repository removed." msgid "Repository edited." msgstr "Usunięto repozytorium." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 #, fuzzy #| msgid "Create Repository" msgid "Edit repository" @@ -2767,7 +2747,7 @@ msgstr "O {box_name}" msgid "{box_name} Manual" msgstr "{box_name} Podręcznik" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2775,35 +2755,35 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 #, fuzzy #| msgid "Enable application" msgid "Manage I2P application" msgstr "Aktywuj aplikację" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 #, fuzzy #| msgid "Go to Networks" msgid "Anonymity Network" msgstr "Przejdź do sieci" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2840,14 +2820,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2856,15 +2836,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki i blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 #, fuzzy #| msgid "Services and Applications" msgid "View and edit wiki applications" @@ -2922,41 +2902,41 @@ msgstr "" "Ta akcja spowoduje usunięcie wszystkich postów, stron oraz komentarzy - w " "tym historii zmian. Trwale usunąć wiki lub blog?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} zostało usunięte." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2964,11 +2944,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -3014,7 +2994,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Informacje o licencji JavaScript" @@ -3034,7 +3014,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Klient czatu" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3044,7 +3024,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3052,15 +3032,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Certyfikaty" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3125,41 +3105,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3169,14 +3149,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3259,7 +3239,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3267,7 +3247,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3276,18 +3256,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3366,49 +3346,49 @@ msgstr "Hasło" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 #, fuzzy #| msgid "Application installed." msgid "Public registrations enabled" msgstr "Aplikacja zainstalowania." -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 #, fuzzy #| msgid "Application installed." msgid "Public registrations disabled" msgstr "Aplikacja zainstalowania." -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 #, fuzzy #| msgid "Application enabled" msgid "Private mode enabled" msgstr "Aplikacja włączona" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 #, fuzzy #| msgid "Application disabled" msgid "Private mode disabled" msgstr "Aplikacja wyłączona" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 #, fuzzy #| msgid "Setting unchanged" msgid "Default skin changed" msgstr "Ustawienie bez zmian" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "Nazwa domeny ustawiona" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "Nazwa domeny ustawiona" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3417,11 +3397,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 #, fuzzy #| msgid "Blocked" msgid "Block Sandbox" @@ -3468,7 +3448,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3639,19 +3619,19 @@ msgstr "" msgid "Services" msgstr "Urządzenie" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3999,7 +3979,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -4104,7 +4084,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -4120,7 +4100,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -4133,7 +4113,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4691,7 +4671,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4702,22 +4682,22 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection refused" msgid "Connect to VPN services" msgstr "Odmowa dostępu" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4727,61 +4707,29 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4790,33 +4738,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4825,87 +4773,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4939,29 +4887,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5005,8 +4953,8 @@ msgstr "" "Obecnie uruchomiona jest instalacja lub aktualizacja. Poczekaj aż się " "skończy przed ponownym uruchomieniem lub wyłączeniem." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Uruchom ponownie" @@ -5053,6 +5001,39 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5084,7 +5065,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5095,7 +5076,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -5115,7 +5096,7 @@ msgstr "" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5125,19 +5106,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5198,7 +5179,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Zaktualizowano ustawienia praw dostępu" @@ -5272,7 +5253,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5285,13 +5266,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5300,31 +5281,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5406,17 +5387,17 @@ msgstr "" msgid "Action" msgstr "Akcje" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5446,51 +5427,51 @@ msgstr "Aplikacja wyłączona" msgid "Error disabling share: {error_message}" msgstr "Błąd wyłączenia udziału: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5653,14 +5634,14 @@ msgstr "" msgid "Shaarlier" msgstr "Shaarli" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5669,99 +5650,99 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 #, fuzzy #| msgid "Chat Server" msgid "Server" msgstr "Serwer czatu" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5798,26 +5779,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5825,14 +5806,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5934,7 +5915,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 #, fuzzy #| msgid "Delete %(name)s" msgid "Delete Snapshots" @@ -5984,65 +5965,65 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Repository removed." msgid "manually created" msgstr "Usunięto repozytorium." -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 #, fuzzy #| msgid "Delete %(name)s" msgid "Manage Snapshots" msgstr "Usuń %(name)s" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 #, fuzzy #| msgid "Access rights configuration updated" msgid "Storage snapshots configuration updated" msgstr "Zaktualizowano ustawienia praw dostępu" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 #, fuzzy #| msgid "Delete %(name)s" msgid "Deleted selected snapshots" msgstr "Usuń %(name)s" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6050,7 +6031,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -6087,16 +6068,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -#, fuzzy -#| msgid "Authentication to remote server failed." -msgid "SSH authentication with password enabled." -msgstr "Nie powiodła się autoryzacja na zdalnym serwerze." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -6111,7 +6082,7 @@ msgstr "" msgid "Logged out successfully." msgstr "Partycja rozszerzona." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6119,147 +6090,147 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bajtów" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 #, fuzzy #| msgid "The requested domain is already registered." msgid "The device is already mounted." msgstr "Wnioskowana domena jest już zarejstrowana." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid directory name." msgstr "Niewłaściwa nazwa hosta" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6299,7 +6270,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Rozszerz główną partycję" @@ -6319,30 +6290,30 @@ msgstr "" "Proszę najpierw utworzyć kopię bezpieczeństwa. Po tej operacji twoja główna " "partycja będzie zwiększona o %(expandable_root_size)s." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Błąd rozszerzania partycji: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Partycja rozszerzona." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6350,7 +6321,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6362,20 +6333,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6384,47 +6355,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6526,13 +6497,13 @@ msgstr "Usługa dynamicznego DNS" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Podczas konfiguracji wystąpił błąd." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6590,14 +6561,14 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Tiny Tiny RSS can be accessed by any użytkownik za pomocą {box_name} loginu " "może mieć dostęp do Tiny Tiny RSS, gdy ten jest włączony." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6627,12 +6598,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6640,8 +6611,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -6649,30 +6620,30 @@ msgstr "" msgid "Software Update" msgstr "Archiwum zostało usunięte." -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox Foundation" msgid "FreedomBox Updated" msgstr "Fundacja FreedomBox" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "User registrations disabled" msgid "Distribution update started" msgstr "Rejestracja użytkowników wyłączona" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6836,55 +6807,55 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Rejestracja użytkowników wyłączona" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "User registrations disabled" msgid "Distribution upgrade disabled" msgstr "Rejestracja użytkowników wyłączona" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "User registrations disabled" msgid "Starting distribution upgrade test." msgstr "Rejestracja użytkowników wyłączona" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6892,15 +6863,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6920,25 +6891,25 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 #, fuzzy #| msgid "Administrator Account" msgid "Authorization Password" msgstr "Konto Administratora" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Show password" msgid "Invalid password." msgstr "Pokaż hasło" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6947,12 +6918,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Tworzenie użytkownika LDAP nie udało się: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Nieudane dodanie użytkownika do {group} grupy:{error}" @@ -6968,43 +6939,43 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 #, fuzzy #| msgid "Failed to add new user to admin group." msgid "Failed to change user status." msgstr "Nieudane dodawanie użytkownika do grupy admin." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Nieudane dodawanie użytkownika do grupy admin: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Utworzono konto użytkownika, możesz się teraz zalogować" @@ -7021,12 +6992,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -7069,17 +7040,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -7110,34 +7081,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7494,7 +7465,7 @@ msgstr "Bezpośrednie połłączenie z internetem." msgid "Server deleted." msgstr "Archiwum zostało usunięte." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7503,7 +7474,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7512,26 +7483,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 #, fuzzy #| msgid "Wiki and Blog" msgid "Website and Blog" @@ -7547,7 +7518,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7560,7 +7531,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7568,11 +7539,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7624,114 +7595,108 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing Backups" -msgid "Error running apt-get" -msgstr "Istniejące kopie zapasowe" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "plik konfiguracyjny: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Instaluj aplikacje" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Błąd podczas instalowania aplikacji: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Błąd podczas instalowania aplikacji: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Błąd podczas instalowania aplikacji: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Błąd podczas instalowania aplikacji: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikacja zainstalowania." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Ostatnie uaktualnienie" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Instaluj aplikacje" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Błąd podczas instalowania aplikacji: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Błąd podczas instalowania aplikacji: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikacja zainstalowania." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7798,56 +7763,56 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "Usługa %(service_name)s nie jest uruchomiona." -#: plinth/templates/base.html:30 -#, fuzzy, python-format -#| msgid "Plinth administrative interface for the %(box_name)s" -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Interfejs administracyjny Plinth dla %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Dom" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Dom" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Aplikacje" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Aplikacje" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Zmień hasło" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Wyłącz" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Wyloguj się" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 #, fuzzy #| msgid "Language" msgid "Select language" msgstr "Język" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Zaloguj się" @@ -8142,6 +8107,40 @@ msgstr "" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Włącz DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Włącz rozszerzenia zabezpieczeń systemu nazw domen" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Proces firewalla nie jest uruchomiony. Proszę go włączyć. Firewall jest " +#~ "domyślnie włączony na %(box_name)s. Na każdym systemie bazującym na " +#~ "Debianie (jak %(box_name)s) możesz go włączyć używając komendy 'service " +#~ "firewalld start' lub, w przypadku systemu z systemd 'systemctl start " +#~ "firewalld'." + +#, fuzzy +#~| msgid "Authentication to remote server failed." +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Nie powiodła się autoryzacja na zdalnym serwerze." + +#, fuzzy +#~| msgid "Existing Backups" +#~ msgid "Error running apt-get" +#~ msgstr "Istniejące kopie zapasowe" + +#, fuzzy, python-format +#~| msgid "Plinth administrative interface for the %(box_name)s" +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Interfejs administracyjny Plinth dla %(box_name)s" + #~ msgid "Access" #~ msgstr "Dostęp" diff --git a/plinth/locale/pt/LC_MESSAGES/django.po b/plinth/locale/pt/LC_MESSAGES/django.po index 0793c57be..60ce22ffd 100644 --- a/plinth/locale/pt/LC_MESSAGES/django.po +++ b/plinth/locale/pt/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Portuguese calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Create new repository" msgid "Name of the new library" msgstr "Criar novo repositório" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1097,22 +1090,22 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 #, fuzzy #| msgid "Repository not found" msgid "Library created." msgstr "Repositório não encontrado" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1150,24 +1143,24 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Administração do Servidor" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Configuração Geral" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Configurar" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1274,47 +1267,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Erro ao definir o nome do hospedeiro: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Nome de hospedeiro definido" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Erro ao definir o nome do domínio: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Nome do domínio definido" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Erro ao definir a página inicial do servidor da Web: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Página inicial do servidor da Web definida" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Erro ao alterar o modo avançado: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "A mostrar as aplicações e funcionalidades avançadas" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1322,7 +1315,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1552,11 +1545,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 #, fuzzy #| msgid "Domain Name" msgid "Dynamic Domain Name" @@ -1672,7 +1665,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1737,13 +1730,13 @@ msgstr "" msgid "Already up-to-date" msgstr "Aplicações" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1869,14 +1862,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1884,7 +1877,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1894,13 +1887,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2041,7 +2034,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2049,7 +2042,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -2071,61 +2064,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2171,7 +2155,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2182,85 +2166,85 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 #, fuzzy #| msgid "Invalid domain name" msgid "Invalid repository URL." msgstr "Nome de domínio inválido" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid domain name" msgid "Invalid repository name." msgstr "Nome de domínio inválido" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 #, fuzzy #| msgid "Repository not found" msgid "Repository's owner name" msgstr "Repositório não encontrado" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Create new repository" msgid "Private repository" msgstr "Criar novo repositório" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Create new repository" msgid "Name of the repository" msgstr "Criar novo repositório" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 #, fuzzy #| msgid "Setting unchanged" msgid "Default branch" msgstr "Definição inalterada" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2311,23 +2295,23 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "Apagar este arquivo permanentemente?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 #, fuzzy #| msgid "Repository not found" msgid "Repository created." msgstr "Repositório não encontrado" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 #, fuzzy #| msgid "Repository not found" msgid "Repository edited." msgstr "Repositório não encontrado" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 #, fuzzy #| msgid "Create new repository" msgid "Edit repository" @@ -2630,7 +2614,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2638,33 +2622,33 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 #, fuzzy #| msgid "Enable application" msgid "Manage I2P application" msgstr "Ativar aplicação" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2709,14 +2693,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2725,15 +2709,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 #, fuzzy #| msgid "Services and Applications" msgid "View and edit wiki applications" @@ -2789,42 +2773,42 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, fuzzy, python-brace-format #| msgid "Archive deleted." msgid "{title} deleted." msgstr "Arquivo apagado." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2832,11 +2816,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2882,7 +2866,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2900,7 +2884,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2910,7 +2894,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2918,15 +2902,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2991,41 +2975,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3035,14 +3019,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3126,7 +3110,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3134,7 +3118,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3143,18 +3127,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3229,49 +3213,49 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 #, fuzzy #| msgid "Applications" msgid "Public registrations enabled" msgstr "Aplicações" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 #, fuzzy #| msgid "Applications" msgid "Public registrations disabled" msgstr "Aplicações" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 #, fuzzy #| msgid "Applications" msgid "Private mode enabled" msgstr "Aplicações" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 #, fuzzy #| msgid "Applications" msgid "Private mode disabled" msgstr "Aplicações" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 #, fuzzy #| msgid "Setting unchanged" msgid "Default skin changed" msgstr "Definição inalterada" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "Nome do domínio definido" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "Nome do domínio definido" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3280,11 +3264,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3331,7 +3315,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3496,19 +3480,19 @@ msgstr "" msgid "Services" msgstr "Descoberta do Serviço" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3858,7 +3842,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3963,7 +3947,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3979,7 +3963,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3992,7 +3976,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4556,7 +4540,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4567,22 +4551,22 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection refused" msgid "Connect to VPN services" msgstr "Conexão recusada" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4592,61 +4576,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4655,33 +4607,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4690,87 +4642,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4804,29 +4756,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4868,8 +4820,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4911,6 +4863,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4942,7 +4925,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4953,7 +4936,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4973,7 +4956,7 @@ msgstr "" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4983,19 +4966,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5056,7 +5039,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 #, fuzzy #| msgid "Configuration updated" msgid "Access rights configuration updated" @@ -5125,7 +5108,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5138,13 +5121,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5153,31 +5136,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 #, fuzzy #| msgid "Network Time Server" msgid "Network File Storage" @@ -5263,17 +5246,17 @@ msgstr "Nome do arquivo" msgid "Action" msgstr "Aplicações" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "Freedombox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5303,51 +5286,51 @@ msgstr "Aplicações" msgid "Error disabling share: {error_message}" msgstr "Erro a instalar a aplicação: {error}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "Permitir o uso desta aplicação por todos." @@ -5507,14 +5490,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5523,97 +5506,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5650,26 +5633,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5677,14 +5660,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5778,7 +5761,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5826,61 +5809,61 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Repository not found" msgid "manually created" msgstr "Repositório não encontrado" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 #, fuzzy #| msgid "Configuration updated" msgid "Storage snapshots configuration updated" msgstr "Configuração atualizada" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5888,7 +5871,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5923,14 +5906,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5943,7 +5918,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5951,149 +5926,149 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 #, fuzzy #| msgid "Service discovery server is running" msgid "The device is already unmounting." msgstr "O Servidor da descoberta do serviço está a correr" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "Esta operação pode ligar um disco que esteja no estado de adormecido." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid domain name" msgid "Invalid directory name." msgstr "Nome de domínio inválido" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 #, fuzzy #| msgid "Archive name" msgid "Share" msgstr "Nome do arquivo" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6127,7 +6102,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6145,31 +6120,31 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, fuzzy, python-brace-format #| msgid "Error setting language: {exception}" msgid "Error expanding partition: {exception}" msgstr "Erro ao definir a língua: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6177,7 +6152,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6189,20 +6164,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6211,47 +6186,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6353,13 +6328,13 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "General Configuration" msgid "Updating configuration" msgstr "Configuração Geral" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6412,31 +6387,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6444,12 +6419,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6457,8 +6432,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -6466,30 +6441,30 @@ msgstr "" msgid "Software Update" msgstr "Arquivo apagado." -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox Updated" msgstr "Freedombox" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 #, fuzzy #| msgid "Applications" msgid "Distribution update started" msgstr "Aplicações" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6651,55 +6626,55 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Aplicações" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 #, fuzzy #| msgid "Applications" msgid "Distribution upgrade disabled" msgstr "Aplicações" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Applications" msgid "Starting distribution upgrade test." msgstr "Aplicações" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6707,15 +6682,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6735,23 +6710,23 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Upload Password" msgid "Invalid password." msgstr "Palavra-passe de Envio" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6760,12 +6735,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6781,41 +6756,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6832,12 +6807,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6875,17 +6850,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6917,34 +6892,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7289,7 +7264,7 @@ msgstr "Erro a estabelecer ligação ao servidor: {}" msgid "Server deleted." msgstr "Arquivo apagado." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7298,7 +7273,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7307,26 +7282,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7340,7 +7315,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7353,7 +7328,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7361,11 +7336,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7415,117 +7390,111 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing Backups" -msgid "Error running apt-get" -msgstr "Backups existentes" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 #, fuzzy #| msgid "Setting unchanged" msgid "media change" msgstr "Definição inalterada" -#: plinth/package.py:395 +#: plinth/package.py:354 #, fuzzy, python-brace-format #| msgid "Configuration" msgid "configuration file: {file}" msgstr "Configuração" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install" msgid "Installing app" msgstr "Instalar" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Erro a instalar a aplicação: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Erro a instalar a aplicação: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Erro a instalar a aplicação: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Erro a instalar a aplicação: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplicação instalada." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Name" msgid "App updated" msgstr "Nome" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install" msgid "Uninstalling app" msgstr "Instalar" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Erro a instalar a aplicação: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Erro a instalar a aplicação: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplicação instalada." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7577,55 +7546,56 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "O Servidor da descoberta do serviço não está a correr" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 #, fuzzy #| msgid "Language" msgid "Select language" msgstr "Língua" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -7891,6 +7861,17 @@ msgstr "" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Ativar DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Ativar Extensões de segurança do Sistema de Nomes de Domínio" + +#, fuzzy +#~| msgid "Existing Backups" +#~ msgid "Error running apt-get" +#~ msgstr "Backups existentes" + #, fuzzy #~| msgid "Configuration updated" #~ msgid "Tor configuration is being updated" diff --git a/plinth/locale/ru/LC_MESSAGES/django.po b/plinth/locale/ru/LC_MESSAGES/django.po index b39a27ed7..e0a97ccf9 100644 --- a/plinth/locale/ru/LC_MESSAGES/django.po +++ b/plinth/locale/ru/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-10-10 18:05+0000\n" "Last-Translator: Nikita Epifanov \n" "Language-Team: Russian calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1049,23 +1042,23 @@ msgstr "" "получить доступ к приложению. Все пользователи с доступом могут использовать " "все библиотеки." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Использовать библиотеки электронных книг calibre" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Электронная библиотека" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Название новой библиотеки" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1073,7 +1066,7 @@ msgstr "" "Только буквы английского алфавита и цифры, без пробелов и специальных " "символов. Пример: My_Library_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Библиотека с таким названием уже существует." @@ -1121,20 +1114,20 @@ msgstr "Перейти в библиотеку %(library)s" msgid "Delete library %(library)s" msgstr "Удалить библиотеку %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Библиотека создана." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Ошибка при создании библиотеки." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} удален." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Не удалось удалить {name}: {error}" @@ -1182,7 +1175,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Администрирование сервера" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1190,18 +1183,18 @@ msgstr "" "Здесь вы можете установить такие опции конфигурации, как имя хоста, доменное " "имя, домашняя страница веб-сервера и тому подобное." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Общие настройки" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Настроить" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1315,47 +1308,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Ошибка параметра hostname: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Смена имени хоста" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Ошибка параметра имени домена: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Смена доменного имени" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Ошибка параметра домашней страницы веб-сервера: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Установка домашней страницы веб-сервера" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Ошибка при изменении расширенного режима: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Показать продвинутые приложения и функции" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Скрыть продвинутые приложения и функции" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1367,7 +1360,7 @@ msgstr "" "коммуникационные серверы могут использовать его для установления вызова " "между сторонами, которые иначе не могут подключиться друг к другу." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse или ejabberd, должны быть настроены с указанными здесь деталями." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP-помощник" @@ -1441,11 +1434,11 @@ msgstr "Ошибка установки часового пояса: {exception} msgid "Time zone set" msgstr "Смена часового пояса" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge это клиент BitTorrent, имеющий веб-интерфейс." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1453,16 +1446,16 @@ msgstr "" "Пароль по умолчанию - 'deluge', но вы должны войти в систему и изменить его " "сразу после включения этой службы." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Загружать файлы используя приложения BitTorrent" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Delugе" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Веб-клиент BitTorrent" @@ -1590,7 +1583,7 @@ msgstr "Результат" msgid "Diagnostic Test" msgstr "Диагностический тест" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1601,7 +1594,7 @@ msgstr "" "адрес, другим может быть трудно найти вас в Интернете. Это помешает другим " "найти службы, предоставляемые {box_name}." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1618,7 +1611,7 @@ msgstr "" "сервер будет назначать DNS-имя на новый IP-адрес, и если кто-то из Интернета " "запрашивает DNS-имя, они будут получать ответ ваш текущий IP-адрес." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1631,11 +1624,11 @@ msgstr "" "обновления URL-адреса на freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Клиент динамического DNS" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Динамическое доменное имя" @@ -1763,7 +1756,7 @@ msgstr "Это поле обязательно." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1818,7 +1811,7 @@ msgstr "Сервер отказал в соединении" msgid "Already up-to-date" msgstr "Уже обновлено" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1826,7 +1819,7 @@ msgstr "" "XMPP является открытым и стандартизированным коммуникационным протоколом. " "Здесь вы можете запустить и настроить сервер XMPP, называемый ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client XMPP клиент. Когда включен, ejabberd доступен всем пользователям {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn или настройте внешний сервер." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "еjabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Чат-сервер" @@ -1973,7 +1966,7 @@ msgstr "" "пользователей будет выглядеть как username@%(domainname)s. Вы можете " "настроить ваш домен на странице Настройка." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1983,7 +1976,7 @@ msgstr "" "Postfix отправляет и принимает почту. Dovecot предоставляет доступ почтовым " "клиентам по протоколоам IMAP и POP3. Rspamd фильтрует спам." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1996,7 +1989,7 @@ msgstr "" "электронную почту. Некоторые снимают ограничения после запроса. " "Дополнительную информацию см. на странице руководства." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2012,7 +2005,7 @@ msgstr "" "\", создаются автоматически и переадресуют на адрес администратора, " "созданный первым." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2020,7 +2013,7 @@ msgstr "" "Приложение Roundcube предоставляет " "пользователям веб-интерфейс для доступа к электронной почте." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2151,7 +2144,7 @@ msgstr "Порт" msgid "Host/Target/Value" msgstr "Хост/Цель/Значение" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2163,7 +2156,7 @@ msgstr "" "правильно настроенным, чтобы уменьшить риск информационной опасности из " "Интернета." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Брандмауэр" @@ -2183,53 +2176,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Порт {name} ({details}) недоступен для внешних сетей" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Демон брандмауэра не выполняется. Пожалуйста, запустите его. На %(box_name)s " -"межсетевой экран включен по умолчанию. На любюй системе, базирующейся на " -"Debian (как и %(box_name)s) которые вы можете запустить его с помощью " -"команды 'service firewalld start' или в случае системы с systemd 'systemctl " -"start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Служба/Порт" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Включено" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Выключено" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Разрешено" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Разрешено (только внутренние)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Разрешено (только внешние)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Заблокировано" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2239,13 +2218,13 @@ msgstr "" "разрешается в брандмауэре и при отключении службы она также запрещается в " "брандмауэре." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Дополнительные" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2299,7 +2278,7 @@ msgstr "Начать установку" msgid "Setup Complete" msgstr "Установка Завершена" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2318,7 +2297,7 @@ msgstr "" "нескольких доступных графических клиентов. И вы можете поделиться своим " "кодом с людьми по всему миру." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2326,69 +2305,69 @@ msgstr "" "Чтобы узнать больше о том, как использовать Git, посетите Git tutorial." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Доступ к Git-репозиторию с возможностью чтения и записи" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Простой хостинг Git" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Неверный URL репозитория." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Неверное имя репозитория." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "Имя нового репозитория или URL для импорта существующего репозитория." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Описание репозитория" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Дополнительно, для показа на Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Имя владельца репозитория" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Частный репозиторий" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" "Доступ к этому репозиторий разрешён только авторизованным пользователям." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Репозиторий с таким именем уже существует." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Имя репозитория" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" "Буквенно-цифровая строка, которая однозначно идентифицирует репозиторий." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Ветка по умолчанию" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb отображает это как ветку по умолчанию." @@ -2432,19 +2411,19 @@ msgstr "Удалить репозиторий Git %(name)s" msgid "Delete this repository permanently?" msgstr "Удалить этот репозиторий навсегда?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Репозиторий создан." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Ошибка при создании репозитория." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Репозиторий отредактирован." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Редактировать репозиторий" @@ -2804,7 +2783,7 @@ msgstr "О {box_name}" msgid "{box_name} Manual" msgstr "Руководство {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2816,7 +2795,7 @@ msgstr "" "обеспечивает анонимность, отправляя зашифрованный трафик через сеть, " "управляемую волонтерами, по всему миру." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2824,26 +2803,26 @@ msgstr "" "Более подробную информацию об I2P можно найти на домашней странице их проекта." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" "При первом посещении веб-интерфейса будет запущен процесс конфигурации." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Управление приложением I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Анонимная сеть" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Прокси" @@ -2888,7 +2867,7 @@ msgstr "" "сети. Скачайте файлы, добавив торренты, или создайте новый торрент, чтобы " "поделиться файлом." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2898,7 +2877,7 @@ msgstr "" "облегченных языков разметки, включая Markdown, и общие функции ведения " "блогов, такие как комментарии и RSS-каналы." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2912,15 +2891,15 @@ msgstr "" "href=\"{users_url}\">Конфигурация пользователей вы можете изменить " "разрешения или добавить новых пользователей." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Вики и Блог" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Просмотр и редактирование приложений Wiki" @@ -2976,41 +2955,41 @@ msgstr "" "Это действие приведет к удалению всех постов, страниц и комментариев, " "включая историю изменений. Окончательно удалить этот вики или блог?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Создать вики {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Не удалось создать вики: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Созданный блог {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Не удалось создать блог: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} удалён." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Не удалось удалить {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted это сервер для Gobby, совместный текстовый редактор." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3021,11 +3000,11 @@ msgstr "" "a>, настольный клиент и установите его. Затем запустите Gobby и выберите " "«Подключиться к серверу» и введите доменное имя вашего {box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Сервер Gobby" @@ -3075,7 +3054,7 @@ msgstr "Видеокомната Janus" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Информация о лицензии JavaScript" @@ -3095,7 +3074,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Чат-клиент" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3109,7 +3088,7 @@ msgstr "" "автоматически получать и устанавливать цифровые сертификаты для каждого " "доступного домена." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3122,15 +3101,15 @@ msgstr "" "org/repository/\">Let's Encrypt Subscriber Agreement перед " "использованием этой службы." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Сертификаты" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Невозможно провести тестирование: Не настроены домены." @@ -3195,7 +3174,7 @@ msgstr "" "Домены не настроены. Настройте домены, чтобы " "иметь возможность получать для них сертификаты." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3204,34 +3183,34 @@ msgstr "" "Сертификат успешно отменен для домена {domain}. Для принятия изменений может " "потребоваться время." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Не удалось отозвать сертификат для домена {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Сертификат успешно получен для домена {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Не удалось получить сертификат для домена {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Сертификат успешно удален для домена {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Не удалось удалить сертификат для домена {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3248,7 +3227,7 @@ msgstr "" "одном сервере Matrix могут общаться с пользователями на всех остальных " "серверах." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3258,7 +3237,7 @@ msgstr "" "Установите приложение Coturn или настройте " "внешний сервер." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3367,7 +3346,7 @@ msgstr "" "Пожалуйста, посетите Let's Encrypt, " "чтобы получить его." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3379,7 +3358,7 @@ msgstr "" "редактируемого сайта. Вы можете использовать mediawiki как сайт, делать " "заметки или работать совместно с друзьями." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3394,7 +3373,7 @@ msgstr "" "перейдя в раздел Special:CreateAccount." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3402,12 +3381,12 @@ msgstr "" "Кто угодно, имея ссылку на wiki, может читать её. Только зарегистрированные " "пользователи могут вносить изменения." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3490,35 +3469,35 @@ msgstr "Пароль обновлен" msgid "Password update failed. Please choose a stronger password" msgstr "Не удалось обновить пароль. Пожалуйста, выберите более надежный пароль" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Публичная регистрация включена" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Публичная регистрация отключена" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Режим приватности включен" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Режим приватности выключен" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Скин по умолчанию изменен" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Доменное имя обновлено" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Название сайта обновлено" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3531,11 +3510,11 @@ msgstr "" "умолчанию (30000). Для подключения к серверу необходим клиент Minetest." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Песочница" @@ -3587,7 +3566,7 @@ msgstr "" msgid "Address" msgstr "Адрес" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3773,7 +3752,7 @@ msgstr "Sеcure Shell" msgid "Services" msgstr "Службы" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3781,7 +3760,7 @@ msgstr "" "Настроить сетевые устройства. Подключайтесь к Интернету через Ethernet, Wi-" "Fi или PPPoE. Поделитесь этим подключением с другими устройствами в сети." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3789,7 +3768,7 @@ msgstr "" "Устройства, администрируемые другими методами, могут быть недоступны для " "настройки здесь." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Сети" @@ -4224,7 +4203,7 @@ msgstr "Редактирование подключения" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Редактировать" @@ -4329,7 +4308,7 @@ msgstr "IРv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Метод" @@ -4345,7 +4324,7 @@ msgstr "DNS-сервер" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "По умолчанию" @@ -4358,7 +4337,7 @@ msgid "This connection is not active." msgstr "Это подключение не активно." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Безопасность" @@ -4944,7 +4923,7 @@ msgstr "Подключение {name} удалено." msgid "Failed to delete connection: Connection not found." msgstr "Не удалось удалить подключение: соединение не найдено." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4962,20 +4941,20 @@ msgstr "" "также получить доступ к остальной части Интернет через {box_name} для " "дополнительной безопасности и анонимности." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Подключение к службам VPN" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Виртуальная частная сеть" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4986,58 +4965,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Миграция на ECC" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Ваша установка OpenVPN в настоящее время использует RSA. Переход на " -"современную криптографию Elliptic Curve Cryptography повышает скорость " -"установления соединения и безопасность. Эта операция необратима. Она должна " -"занять всего несколько минут на большинстве одноплатных компьютеров." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Все новые установки OpenVPN на %(box_name)s будут использовать ECC по " -"умолчанию. Мы рекомендуем выполнить миграцию как можно скорее." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Предупреждение: Существующие профили клиентов будут аннулированы этой " -"операцией. Все пользователи OpenVPN на %(box_name)s должны загрузить свои " -"новые профили. Для подключения к этому серверу следует использовать клиенты " -"OpenVPN, совместимые с ECC." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Мигрировать" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Профиль" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Чтобы подключиться к VPN %(box_name)s, вам необходимо загрузить профиль и " @@ -5046,18 +4988,19 @@ msgstr "" "\" выше, чтобы просмотреть рекомендуемые клиенты и инструкции по их " "настройке." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Профиль специфичен для каждого пользователя %(box_name)s. Держите профиль в " "тайне." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Скачать мой профиль" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5070,19 +5013,19 @@ msgstr "" "недоступны из остальной части интернета. Это включает в себя следующие " "ситуации:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} ограничен брандмауэром." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} подключен к маршрутизатору (беспроводному), который вы не " "контролируете." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5090,7 +5033,7 @@ msgstr "" "Ваш провайдер не предоставляет вам внешний IP-адрес и вместо этого " "обеспечивает подключение к Интернету через NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5098,11 +5041,11 @@ msgstr "" "Ваш провайдер не предоставляет вам статический IP-адрес, и ваш-IP адрес " "изменяется каждый раз при подключении к Интернету." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Ваш провайдер ограничивает входящие соединения." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5115,23 +5058,23 @@ msgstr "" "услуг pagekite, например pagekite.net. " "В будущем, для этого возможно будет использовать {box_name} вашего приятеля." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PаgeKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Публичная видимость" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite Домен" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Домен сервера" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5139,31 +5082,31 @@ msgstr "" "Выберите свой сервер pagekite. Выберите \"pagekite.net\", чтобы использовать " "сервер по умолчанию - pagekite.net." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Порт сервера" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Порт сервера pagekite (по умолчанию: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Имя Kite" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Пример: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Недопустимое имя kite" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite secrеt" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5171,35 +5114,35 @@ msgstr "" "Секрет, связанный с kite или секрет по умолчанию для вашей учетной записи, " "если не секрет устанавливается на kite." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "протокол" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "внешний (frontend) порт" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "Внутренний (freedombox) порт" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Включить поддомены" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Удалить пользовательские службы" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Эта служба уже доступна как стандартная." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Добавить пользовательскую службу" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Эта служба уже существует" @@ -5236,29 +5179,29 @@ msgstr "" "все комбинации протокол/порт, которые вы можете здесь задать. Например, " "HTTPS на портах, отличных от 443, может вызывать проблемы." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Веб-сервер (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Сайт будет доступен на http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Веб-сервер (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Сайт будет доступен на https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Sеcure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5310,8 +5253,8 @@ msgstr "" "Другая установка или обновление уже запущенны. Пожалуйста, подождите " "несколько минут перед выключением или перезагрузкой." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Перезапустить" @@ -5361,6 +5304,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Завершить работу сейчас" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5407,7 +5383,7 @@ msgstr "Web-прокси" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Доступ к {url} с прокси {proxy} на tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5424,7 +5400,7 @@ msgstr "" "клиентов. Для этого могут использоваться как клиенты настольного компьютера, " "так и мобильные версии." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your для десктопов и мобильных устройств." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC-клиент" @@ -5448,7 +5424,7 @@ msgstr "IRC-клиент" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5463,7 +5439,7 @@ msgstr "" "supported-clients\">поддерживаемое клиентское приложение. Доступ к " "Radicale может получить любой пользователь с логином {box_name}." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5473,12 +5449,12 @@ msgstr "" "создание новых календарей и адресных книг. Он не поддерживает добавление " "событий или контактов, для этого требуется отдельный клиент." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Календарь и Адресная книга" @@ -5552,7 +5528,7 @@ msgstr "" "address>) и ваше имя пользователя. Нажав на кнопку поиска будет список " "существующих календарей и адресных книг." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Конфигурация прав доступа обновлена" @@ -5642,7 +5618,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Чтение и подписка на ленты новостей" @@ -5657,7 +5633,7 @@ msgstr "Мост" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5665,7 +5641,7 @@ msgstr "" "Samba позволяет обмениваться файлами и папками между FreedomBox и другими " "компьютерами в вашей локальной сети." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5678,11 +5654,11 @@ msgstr "" "вашем компьютере по адресу \\\\{hostname} (в Windows) или smb://{hostname}." "local (в Linux и Mac). Вы можете выбрать один из трёх типов: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Открытый общий ресурс - доступен всем в вашей локальной сети." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5690,7 +5666,7 @@ msgstr "" "Общий доступ к группе - доступен только пользователям FreedomBox, которые " "находятся в группе Freedombox-share." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5698,15 +5674,15 @@ msgstr "" "Домашняя папка - каждый пользователь в группе Freedombox-share может иметь " "собственное личное пространство." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Доступ к частным общим ресурсам" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Сетевое хранилище файлов" @@ -5795,15 +5771,15 @@ msgstr "Имя общего ресурса" msgid "Action" msgstr "Действие" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "Диск ОС FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Открытый ресурс" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Групповой ресурс" @@ -5829,7 +5805,7 @@ msgstr "Общий доступ отключён." msgid "Error disabling share: {error_message}" msgstr "Ошибка отключения общего доступа: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5837,7 +5813,7 @@ msgstr "" "Searx - это конфиденциальная метапоисковая система. Она агрегирует и " "показывает результаты с разных поисковых систем." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5845,41 +5821,41 @@ msgstr "" "Searx может быть использован, чтобы избежать отслеживания и профилирования " "поисковыми системами. Она не хранит никаких файлов cookie по умолчанию." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Поиск в интернете" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Веб-поиск" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Безопасный Поиск" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Выберите семейный фильтр по умолчанию, чтобы применить к вашим результатам " "поиска." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Умеренный" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Строгий" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Разрешить публичный доступ" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "Разрешите использовать это приложение всем, у кого есть доступ к нему." @@ -6060,7 +6036,7 @@ msgstr "Закладки" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6070,7 +6046,7 @@ msgstr "" "защиты вашего интернет-трафика. Его можно использовать для обхода интернет-" "фильтрации и цензуры." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6083,7 +6059,7 @@ msgstr "" "SOCKS5. Локальные устройства могут подключаться к этому прокси, и их данные " "будут шифроваться и передаваться через сервер Shadowsocks." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6092,42 +6068,42 @@ msgstr "" "в вашем устройстве, браузере или приложении на http://" "freedombox_address:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Прокси Socks5" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Рекомендуется" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Сервер" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Имя или IP адрес сервера" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Номер порта сервера" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Пароль, используемый для шифрования данных. Должен совпадать с паролем " "сервера." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Метод шифрования. Должен соответствовать параметру на сервере." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6136,15 +6112,15 @@ msgstr "" "Общий доступ позволяет обмениваться файлами и папками на вашем {box_name} " "через сеть с выбранными группами пользователей." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Общий доступ" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Имя общего ресурса" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6152,37 +6128,37 @@ msgstr "" "Цифро-буквенная строка в нижнем регистре, однозначно идентифицирующая " "ресурс. Пример: media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Путь к общему ресурсу" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Путь к папке на диске этого сервера, которую вы хотите сделать общей." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Публичный доступ" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Сделайте файлы в этой папке доступными для всех, у кого есть ссылка." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Группы пользователей, которые могут читать файлы в общей папке:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "Пользователи выбранных групп смогут читать файлы в общей папке." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Общий ресурс с таким именем уже существует." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" "Общий доступ должны быть публично доступным или доступными хотя бы для одной " @@ -6221,19 +6197,19 @@ msgstr "Общий ресурс добавлен." msgid "Add Share" msgstr "Добавить общий ресурс" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Общий ресурс изменён." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Редактировать общий ресурс" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Общий ресурс удалён." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6243,7 +6219,7 @@ msgstr "" "btrfs. Они могут использоваться для отката системы к последнему рабочему " "состоянию в случае неприемлемых изменений в системе." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6254,7 +6230,7 @@ msgstr "" "до и после инсталляции программного обеспечения. Старые снимки автоматически " "удаляются в соответствии с установками ниже." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups, так как они хранятся на том же разделе. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Хранилище снимков" @@ -6368,7 +6344,7 @@ msgstr "Дата" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Удалить снапшот" @@ -6420,57 +6396,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Откат к снимку %(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "создано вручную" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "временная шкала" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Управление снапшотами" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Создан снимок." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Настройки хранения снапшотов обновлены" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Ошибка действий: {0}[{1}][{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Удалить выбранные снапшоты" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Снимок сейчас используется. Попробуйте позже." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Откат к снимку #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Необходимо перезагрузить систему для завершения отката." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Откат к снимку" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6482,7 +6458,7 @@ msgstr "" "может выполнять задачи администрирования, копировать файлы или запускать " "другие службы с использованием таких соединений." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Secure Shell (SSH) сервер" @@ -6520,14 +6496,6 @@ msgstr "Алгоритм" msgid "Fingerprint" msgstr "Отпечаток" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "SSH-аутентификация с отключенным паролем." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "SSH-аутентификация с включённым паролем." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Единый вход" @@ -6540,7 +6508,7 @@ msgstr "Логин" msgid "Logged out successfully." msgstr "Выход выполнен успешно." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6551,107 +6519,107 @@ msgstr "" "{box_name}. Вы можете видеть, какие носители используются, монтировать и " "размонтировать подключаемые носители, увеличивать корневой раздел итп." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Хранилище" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} байт" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} КиБ" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} Миб" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} Гиб" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} Тиб" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Операция не удалась." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Операция была отменена." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Устройство уже отключается." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" "Операция не поддерживается из-за отсутствия поддержки драйвера или утилиты." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Время операции вышло." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "Операция пробудит диск, находящийся в режиме глубокого сна." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Попытка отключения устройства, которое используется." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Операция уже отменена." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Отсутствует авторизация для выполнения запрошенной операции." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Устройство уже подключено." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Устройство не подключено." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Использование запрошенной опции не разрешено." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Устройство подключено другим пользователем." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Недостаточно места в системном разделе: использовано {percent_used}%, " "свободно {free_space}." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Недостаточно места на диске" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Неизбежный сбой диска" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6660,39 +6628,39 @@ msgstr "" "Диск {id} сообщает, что в ближайшем будущем он может выйти из строя. " "Скопируйте любые данные, пока еще можете, и замените диск." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Неверное имя каталога." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Каталог не существует." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Путь не каталог." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Каталог не читается пользователем." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Каталог не доступен для записи пользователем." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Каталог" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Подкаталог (необязательно)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Поделиться" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Другой каталог (укажите ниже)" @@ -6730,7 +6698,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Расширить корневой раздел" @@ -6754,30 +6722,30 @@ msgstr "" "этой операции будет доступно %(expandable_root_size)s свободного места в " "вашем корневом разделе." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Ошибка расширения раздела: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Раздел успешно расширен." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor}{drive_model} может быть безопасно отсоединено." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Устройство может быть безопасно отсоединено." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Ошибка извлечения устройства: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6789,7 +6757,7 @@ msgstr "" "или удаление файлов на одном устройстве будет автоматически реплицироваться " "на все другие устройства, на которых работает Syncthing." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6808,20 +6776,20 @@ msgstr "" "собственный набор папок. Веб-интерфейс доступен только для пользователей, " "принадлежащих к группе «admin» или «syncthing-access»." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Администрирование приложения Syncthing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Синхронизация файлов" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6835,7 +6803,7 @@ msgstr "" "\"https://www.torproject.org/download/download-easy.html.en\">Tor Browser." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6843,40 +6811,40 @@ msgid "" msgstr "" "Порт Tor SOCKS доступен на {box_name} для внутренних сетей на TCP-порту 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Сервис Tor Onion" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor Socks прокси" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Ретранслятор Tor типа мост" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Доступен порт трансляции Tor" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 транспорт зарегестрирован" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 транспорт зарегистрирован" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Доступ к {url} по tcp{kind} через Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Подтверждение использования Tor в {url} по tcp {kind}" @@ -6995,13 +6963,13 @@ msgstr "Onion сервис" msgid "Ports" msgstr "Порты" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Произошла ошибка во время настройки." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -7064,7 +7032,7 @@ msgstr "" msgid "Transmission" msgstr "Transmissiоn" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7073,7 +7041,7 @@ msgstr "" "Tiny Tiny RSS это новый (RSS/Atom) агрегатор новостей, позволяющий читать " "новости из любого места, так же удобно, как и в настольных приложениях." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7082,7 +7050,7 @@ msgstr "" "Когда Tiny Tiny RSS включен, доступ к нему может получить любой пользователь, принадлежащий к группе feed-reader." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7091,11 +7059,11 @@ msgstr "" "Tiny RSS используйте URL / tt-rss-app для " "подключения." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Чтение ленты новостей" @@ -7103,12 +7071,12 @@ msgstr "Чтение ленты новостей" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "Проверьте и установите новейшие программы и обновления безопасности." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7122,22 +7090,22 @@ msgstr "" "выполняется автоматически в 02:00, в результате чего все приложения на " "короткое время становятся недоступными." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Обновление программного обеспечения" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox обновлён" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Не удалось запустить обновление дистрибутива" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7147,11 +7115,11 @@ msgstr "" "дистрибутива. Пожалуйста, убедитесь, что свободно не менее 5 ГБ. Обновление " "дистрибутива будет повторно запущено через 24 часа, если это включено." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Началось обновление дистрибутива" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7330,46 +7298,46 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Обновление дистрибутива включено" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Ошибка при настройке автоматического обновления: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Автоматические обновления включены" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Автоматические обновления отключены" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Обновление дистрибутива включено" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Обновление дистрибутива отключено" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Начался процесс обновления." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Не удалось запустить обновление." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Активированы частые обновления функций." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Distribution upgrade enabled" msgid "Starting distribution upgrade test." msgstr "Обновление дистрибутива включено" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7381,7 +7349,7 @@ msgstr "" "запись пользователя была частью группы, чтобы разрешить пользователю доступ " "к приложению." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7393,15 +7361,15 @@ msgstr "" "пользователи группы admin могут изменять приложения или системные " "настройки." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Пользователи и группы" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Доступ ко всем сервисам и настройкам системы" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Проверьте запись LDAP \"{search_item}\"" @@ -7420,11 +7388,11 @@ msgid "" msgstr "" "Требуется. 150 символов или меньше. Только английские буквы, цифры и @/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Пароль авторизации" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7432,11 +7400,11 @@ msgstr "" "Введите пароль пользователя \"{user}\" для авторизации изменений учетной " "записи." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Неправильный пароль." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7450,12 +7418,12 @@ msgstr "" "\" смогут войти во все службы. Они также могут входить в систему через SSH и " "иметь привилегии администратора (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Не удалось создать пользователя LDAP: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Не удалось добавить нового пользователя в группу {group}: {error}" @@ -7475,42 +7443,42 @@ msgstr "" "на каждой строке. Пустые строки и строки, начинающиеся с # будут " "игнорироваться." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Переименование пользователя LDAP не удалось." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Не удалось удалить пользователя из группы." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Не удалось добавить пользователя в группу." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Не удалось задать ключи SSH." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Не удалось изменить статус пользователя." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Изменение LDAP пароля пользователя не удалось." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Не удалось добавить нового пользователя в группу администраторов: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Не удалось ограничить доступ к консоли: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Учетная запись пользователя создана, теперь вы вошли" @@ -7527,12 +7495,12 @@ msgstr "Сохранить пароль" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Создать пользователя" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Удаление пользователя" @@ -7573,13 +7541,19 @@ msgid "The following administrator accounts exist in the system." msgstr "В системе существуют следующие учетные записи администратора." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Удалите эти учетные записи из командной строки и обновите страницу, чтобы " "создать учетную запись, которую можно использовать с %(box_name)s. В " @@ -7588,7 +7562,7 @@ msgstr "" "с %(box_name)s, пропустите этот шаг." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Пользователи" @@ -7621,34 +7595,34 @@ msgstr "" msgid "Save Changes" msgstr "Сохранить изменения" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Пользователь %(username)s создан." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Пользователь %(username)s обновлен." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Редактирование пользователя" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Пользователь {user} удален." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Сбой при удалении LDAP пользователя." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Изменить пароль" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Пароль успешно изменён." @@ -7985,7 +7959,7 @@ msgstr "Удалить соединение с сервером" msgid "Server deleted." msgstr "Сервер удален." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7999,7 +7973,7 @@ msgstr "" "помощью тем. Интерфейс администрирования и созданные веб-страницы подходят " "для мобильных устройств." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8013,7 +7987,7 @@ msgstr "" "ссылки в интерфейсе администратора для улучшения URL-адресов ваших страниц и " "сообщений." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8024,7 +7998,7 @@ msgstr "" "закладку на страницу администратора, " "чтобы в будущем иметь доступ к интерфейсу администрирования." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8034,12 +8008,12 @@ msgstr "" "базы данных из интерфейса администратора. Дополнительные плагины или темы " "могут быть установлены и обновлены на ваш страх и риск." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Сайт и блог" @@ -8056,7 +8030,7 @@ msgstr "" "просматривать сайт или блог WordPress. Включайте только после первоначальной " "настройки WordPress." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8079,7 +8053,7 @@ msgstr "" "месте. Отдельными фотографиями можно поделиться с другими, отправив прямую " "ссылку." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8090,11 +8064,11 @@ msgstr "" "Zoph. Для дополнительных пользователей необходимо создать учетные записи как " "в {box_name}, так и в Zoph с тем же именем пользователя." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Организатор фотографий" @@ -8149,116 +8123,110 @@ msgstr "" msgid "Finished: {name}" msgstr "Служба выключена: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Пакет {expression} недоступен для установки" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Пакет {package_name} последней версией ({latest_version})" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "Ошибка во время резервного копирования" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "Установка" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "Загрузка" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "изменение медиа" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "Файл настроек: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Установка приложений" -#: plinth/setup.py:42 +#: plinth/setup.py:43 #, fuzzy #| msgid "Updating..." msgid "Updating app" msgstr "Обновляется..." -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Ошибка при установке пакетов: {string}{details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Ошибка при установке пакетов: {string}{details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Ошибка при установке приложения: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Ошибка при установке приложения: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Приложение установлено." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Последнее обновление" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Установка приложений" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Ошибка при установке пакетов: {string}{details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Ошибка при установке приложения: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Приложение установлено." -#: plinth/setup.py:451 +#: plinth/setup.py:452 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8320,53 +8288,54 @@ msgstr "Установка" msgid "Service %(service_name)s is not running." msgstr "Служба %(service_name)s не запущена." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Базовая функциональность и веб-интерфейс %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Домой" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Домой" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Приложения" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Приложения" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Система" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Система" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Изменить пароль" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Завершить работу" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Выход" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Выберите язык" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Войти" @@ -8657,6 +8626,78 @@ msgstr "" msgid "Gujarati" msgstr "Гуджарати" +#~ msgid "Enable DNSSEC" +#~ msgstr "Включить DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Включить расширения безопасности системы доменных имен" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Демон брандмауэра не выполняется. Пожалуйста, запустите его. На " +#~ "%(box_name)s межсетевой экран включен по умолчанию. На любюй системе, " +#~ "базирующейся на Debian (как и %(box_name)s) которые вы можете запустить " +#~ "его с помощью команды 'service firewalld start' или в случае системы с " +#~ "systemd 'systemctl start firewalld'." + +#~ msgid "Migrate to ECC" +#~ msgstr "Миграция на ECC" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Ваша установка OpenVPN в настоящее время использует RSA. Переход на " +#~ "современную криптографию Elliptic Curve Cryptography повышает скорость " +#~ "установления соединения и безопасность. Эта операция необратима. Она " +#~ "должна занять всего несколько минут на большинстве одноплатных " +#~ "компьютеров." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Все новые установки OpenVPN на %(box_name)s будут использовать ECC по " +#~ "умолчанию. Мы рекомендуем выполнить миграцию как можно скорее." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Предупреждение: Существующие профили клиентов будут аннулированы " +#~ "этой операцией. Все пользователи OpenVPN на %(box_name)s должны загрузить " +#~ "свои новые профили. Для подключения к этому серверу следует использовать " +#~ "клиенты OpenVPN, совместимые с ECC." + +#~ msgid "Migrate" +#~ msgstr "Мигрировать" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "SSH-аутентификация с отключенным паролем." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "SSH-аутентификация с включённым паролем." + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "Ошибка во время резервного копирования" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Базовая функциональность и веб-интерфейс %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Сетевые подключения" diff --git a/plinth/locale/si/LC_MESSAGES/django.po b/plinth/locale/si/LC_MESSAGES/django.po index d4efbfaab..9d2098172 100644 --- a/plinth/locale/si/LC_MESSAGES/django.po +++ b/plinth/locale/si/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-04-27 13:32+0000\n" "Last-Translator: HelaBasa \n" "Language-Team: Sinhala calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1021,20 +1014,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1072,24 +1065,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1185,47 +1178,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1233,7 +1226,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1463,11 +1456,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1579,7 +1572,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1634,13 +1627,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1762,14 +1755,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1777,7 +1770,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1787,13 +1780,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1918,7 +1911,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1926,7 +1919,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1946,61 +1939,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2046,7 +2030,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2057,73 +2041,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2167,19 +2151,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2472,7 +2456,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2480,31 +2464,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2541,14 +2525,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2557,15 +2541,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2619,41 +2603,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2661,11 +2645,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2711,7 +2695,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2729,7 +2713,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2739,7 +2723,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2747,15 +2731,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2818,41 +2802,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2862,14 +2846,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2950,7 +2934,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2958,7 +2942,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2967,18 +2951,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3047,35 +3031,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3084,11 +3068,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3133,7 +3117,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3292,19 +3276,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3650,7 +3634,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3755,7 +3739,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3771,7 +3755,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3784,7 +3768,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4320,7 +4304,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4331,20 +4315,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4354,61 +4338,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4417,33 +4369,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4452,87 +4404,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4566,29 +4518,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4630,8 +4582,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4673,6 +4625,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4704,7 +4687,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4715,7 +4698,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4735,7 +4718,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4745,19 +4728,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4816,7 +4799,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4883,7 +4866,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4896,13 +4879,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4911,31 +4894,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5013,15 +4996,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5047,51 +5030,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5244,14 +5227,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5260,97 +5243,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5387,26 +5370,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5414,14 +5397,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5515,7 +5498,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5563,57 +5546,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5621,7 +5604,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5654,14 +5637,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5674,7 +5649,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5682,143 +5657,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5852,7 +5827,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5870,30 +5845,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5901,7 +5876,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5913,20 +5888,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5935,47 +5910,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6073,11 +6048,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6129,31 +6104,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6161,12 +6136,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6174,33 +6149,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6348,51 +6323,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6400,15 +6375,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6426,21 +6401,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6449,12 +6424,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6470,41 +6445,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6521,12 +6496,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6564,17 +6539,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6605,34 +6580,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6941,7 +6916,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6950,7 +6925,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6959,26 +6934,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6992,7 +6967,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7005,7 +6980,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7013,11 +6988,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7066,96 +7041,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7206,53 +7177,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/sl/LC_MESSAGES/django.po b/plinth/locale/sl/LC_MESSAGES/django.po index fae756c6e..3b13f5716 100644 --- a/plinth/locale/sl/LC_MESSAGES/django.po +++ b/plinth/locale/sl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Slovenian calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 #, fuzzy #| msgid "Create new repository" msgid "Name of the new library" msgstr "Ustvari novo skladišče" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 #, fuzzy #| msgid "Create remote backup repository" msgid "A library with this name already exists." @@ -1146,22 +1139,22 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 #, fuzzy #| msgid "Repository not found" msgid "Library created." msgstr "Ne najdem skladišča" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1211,24 +1204,24 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Skrbništvo strežnika" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Nastavitve" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1334,47 +1327,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1382,7 +1375,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1615,11 +1608,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 #, fuzzy #| msgid "Domain Name" msgid "Dynamic Domain Name" @@ -1733,7 +1726,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1790,13 +1783,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1920,14 +1913,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1935,7 +1928,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1945,13 +1938,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2090,7 +2083,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2098,7 +2091,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -2118,61 +2111,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2218,7 +2202,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2229,85 +2213,85 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository URL." msgstr "Neveljavno ime gostitelja" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid repository name." msgstr "Neveljavno ime gostitelja" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 #, fuzzy #| msgid "Repository not found" msgid "Repository's owner name" msgstr "Ne najdem skladišča" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 #, fuzzy #| msgid "Create new repository" msgid "Private repository" msgstr "Ustvari novo skladišče" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 #, fuzzy #| msgid "Create remote backup repository" msgid "A repository with this name already exists." msgstr "Ustvari oddaljeno skladišče za rezervne kopije" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 #, fuzzy #| msgid "Create new repository" msgid "Name of the repository" msgstr "Ustvari novo skladišče" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2358,23 +2342,23 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "Želite ta arhiv trajno izbrisati?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 #, fuzzy #| msgid "Repository not found" msgid "Repository created." msgstr "Ne najdem skladišča" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 #, fuzzy #| msgid "Repository not found" msgid "Repository edited." msgstr "Ne najdem skladišča" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 #, fuzzy #| msgid "Create new repository" msgid "Edit repository" @@ -2669,7 +2653,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2677,31 +2661,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2738,14 +2722,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2754,15 +2738,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2816,42 +2800,42 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, fuzzy, python-brace-format #| msgid "Archive deleted." msgid "{title} deleted." msgstr "Arhiv je izbrisan." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2859,11 +2843,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2909,7 +2893,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2927,7 +2911,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2937,7 +2921,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2945,15 +2929,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3016,41 +3000,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3060,14 +3044,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3148,7 +3132,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3156,7 +3140,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3165,18 +3149,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3247,39 +3231,39 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain Name" msgid "Domain name updated" msgstr "Ime domene" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain Name" msgid "Site name updated" msgstr "Ime domene" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3288,11 +3272,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3337,7 +3321,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3500,19 +3484,19 @@ msgstr "" msgid "Services" msgstr "Odkrivanje storitev" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3858,7 +3842,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3963,7 +3947,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3979,7 +3963,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3992,7 +3976,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4540,7 +4524,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4551,22 +4535,22 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 #, fuzzy #| msgid "Connection refused" msgid "Connect to VPN services" msgstr "Povezava je zavrnjena" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4576,61 +4560,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4639,33 +4591,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4674,87 +4626,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4788,29 +4740,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4852,8 +4804,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4895,6 +4847,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4926,7 +4909,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4937,7 +4920,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4957,7 +4940,7 @@ msgstr "" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4967,19 +4950,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5038,7 +5021,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -5113,7 +5096,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5126,13 +5109,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5141,31 +5124,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5245,17 +5228,17 @@ msgstr "" msgid "Action" msgstr "Šifriranje" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5283,51 +5266,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5482,14 +5465,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5498,97 +5481,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5625,26 +5608,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5652,14 +5635,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5753,7 +5736,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5801,59 +5784,59 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Repository not found" msgid "manually created" msgstr "Ne najdem skladišča" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5861,7 +5844,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5896,14 +5879,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5916,7 +5891,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5924,145 +5899,145 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid directory name." msgstr "Neveljavno ime gostitelja" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6096,7 +6071,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6114,30 +6089,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6145,7 +6120,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6157,20 +6132,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6179,47 +6154,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6317,13 +6292,13 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "Configuration updated" msgid "Updating configuration" msgstr "Konfiguracija je posodobljena" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6384,14 +6359,14 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Cockpit will be available from /" @@ -6406,17 +6381,17 @@ msgstr "" "\"{users_url}\">katerikoli uporabnik na {box_name}, ki je član skupine " "skrbnikov." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6424,12 +6399,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6437,8 +6412,8 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 #, fuzzy @@ -6446,28 +6421,28 @@ msgstr "" msgid "Software Update" msgstr "Arhiv je izbrisan." -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox Updated" msgstr "FreedomBox" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6617,51 +6592,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6669,15 +6644,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6697,23 +6672,23 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 #, fuzzy #| msgid "Invalid hostname" msgid "Invalid password." msgstr "Neveljavno ime gostitelja" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6722,12 +6697,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6743,41 +6718,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6794,12 +6769,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6837,17 +6812,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6878,34 +6853,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7246,7 +7221,7 @@ msgstr "Napaka ob nameščanju aplikacije: {error}" msgid "Server deleted." msgstr "Arhiv je izbrisan." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7255,7 +7230,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7264,26 +7239,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7297,7 +7272,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7310,7 +7285,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7318,11 +7293,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7372,112 +7347,106 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing backups" -msgid "Error running apt-get" -msgstr "Obstoječe rezervne kopije" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Napaka ob nameščanju aplikacije: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Napaka ob nameščanju aplikacije: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikacija je nameščena." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Name" msgid "App updated" msgstr "Ime" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Napaka ob nameščanju aplikacije: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikacija je nameščena." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7528,53 +7497,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Aplikacije" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -7839,6 +7809,17 @@ msgstr "" msgid "Gujarati" msgstr "" +#~ msgid "Enable DNSSEC" +#~ msgstr "Omogoči DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Omogoči varnostne razširitve DNSSEC" + +#, fuzzy +#~| msgid "Existing backups" +#~ msgid "Error running apt-get" +#~ msgstr "Obstoječe rezervne kopije" + #, fuzzy #~| msgid "Archive deleted." #~ msgid "Server URL updated" diff --git a/plinth/locale/sq/LC_MESSAGES/django.po b/plinth/locale/sq/LC_MESSAGES/django.po index d294869e7..e67a2e54a 100644 --- a/plinth/locale/sq/LC_MESSAGES/django.po +++ b/plinth/locale/sq/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-10-10 13:34+0000\n" "Last-Translator: Besnik Bleta \n" "Language-Team: Albanian calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1046,23 +1039,23 @@ msgstr "" "gjendje të përdorin aplikacionin. Krejt përdoruesit e lejuar mund të hyjnë " "në të gjitha bibliotekat." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Përdorni biblioteka calibre e-librash" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Bibliotekë E-librash" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Emër i bibliotekës së re" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1070,7 +1063,7 @@ msgstr "" "Vetëm shkronja të alfabetit të anglishtes, numra dhe shenjat _ . dhe - pa " "hapësira apo shenja speciale. Shembull: Mediateka_ime_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Ka tashmë një bibliotekë me atë emër." @@ -1118,20 +1111,20 @@ msgstr "Kalo te biblioteka %(library)s" msgid "Delete library %(library)s" msgstr "Fshije bibliotekën %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Biblioteka u krijua." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Ndodhi një gabim teksa krijohej biblioteka." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} u fshi." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "S’u fshi dot {name}: {error}" @@ -1181,7 +1174,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Administrim Shërbyesi" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1189,18 +1182,18 @@ msgstr "" "Këtu mund të caktoni disa nga mundësitë e përgjithshme të formësimit, bie " "fjala strehëemër, emër përkatësie, faqe hyrëse e sgërbyesit." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Formësim i Përgjithshëm" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Formësoni" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1315,47 +1308,47 @@ msgstr "" "Regjistrat përmbajnë informacion se cilët kanë hyrë në sistem dhe hollësi " "diagnostikimi nga shërbime të ndryshme" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Gabim në caktim strehëemri: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Strehëemri u caktua" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Gabim në caktimin e emrin të përkatësisë: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Emri i përkatësisë u caktua" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Gabim në caktim faqeje hyrëse shërbyesi: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Faqja hyrëse e shërbyesit u caktua" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Gabim në ndryshimin e mënyrës së thelluar: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Me aplikacione dhe veçori të thelluara shfaqur" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Me aplikacione dhe veçori të thelluara fshehur" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1368,7 +1361,7 @@ msgstr "" "thirrje mes palësh që, përndryshe, s’janë në gjendje të lidhen me njëri-" "tjetrin." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse, ose ejabberd duhen formësuar me hollësitë e dhëna këtu." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "Ndihmës VoIP" @@ -1441,11 +1434,11 @@ msgstr "Gabim në ujdisje zone kohore: {exception}" msgid "Time zone set" msgstr "Zona kohore u caktua" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge është një klient BitTorrent që përmban një UI Web." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1453,16 +1446,16 @@ msgstr "" "Fjalëkalimi parazgjedhje është “deluge”, por duhet të bëni hyrjen me të dhe " "ta ndryshoni menjëherë pas aktivizimit të këtij shërbimi." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Shkarkoni kartela duke përdorur aplikacione BitTorrent" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Klient Web BitTorrent" @@ -1590,7 +1583,7 @@ msgstr "Përfundim" msgid "Diagnostic Test" msgstr "Test Diagnostikimesh" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1602,7 +1595,7 @@ msgstr "" "Internet. Kjo do t’u pengojë të tjerëve të gjejnë shërbime të cilat ofrohen " "nga ky {box_name}." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1620,7 +1613,7 @@ msgstr "" "emrin tuaj DNS me IP-në e re, dhe nëse dikush në Internet kërkon për emrin " "tuaj DNS, do të marrë një përgjigje me adresën tuaj aktuale IP." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1633,11 +1626,11 @@ msgstr "" "bazë përditësim URL-je, te freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Klient DNS Dinamik" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Emër Dinamik Përkatësie" @@ -1768,7 +1761,7 @@ msgstr "Kjo fushë është e domosdoshme." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1823,7 +1816,7 @@ msgstr "Shërbyesi hodhi poshtë lidhjen" msgid "Already up-to-date" msgstr "I përditësuar tashmë" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1831,7 +1824,7 @@ msgstr "" "XMPP është një protokoll i hapët dhe i standardizuar komunikimesh. Këtu mund " "të vini në punë dhe formësoni shërbyesin tuaj XMPP, të quajtur ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client me hyrje {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn, ose formësoni një shërbyes " "të jashtëm." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Shërbyes Fjalosjesh" @@ -1985,7 +1978,7 @@ msgstr "" "Përkatësinë tuaj mund ta ujdisni te faqja Formësoni e sistemit." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1996,7 +1989,7 @@ msgstr "" "të përdorin kutinë tuaj postare përmes IMAP apo POP3. Rspamd trajton " "mesazhet e padëshiruar." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -2009,7 +2002,7 @@ msgstr "" "kërkese shprehimisht për këtë. Për më tepër hollësi, shihni faqen e " "doracakut." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2018,13 +2011,14 @@ msgid "" "Necessary aliases such as \"postmaster\" are automatically created pointing " "to the first admin user." msgstr "" -"Çdo përdorues në {box_name} merr një adresë email të ngjashme me përdorues@" -"përkatësiaime.shembull. Do të marrë gjithashtu email nga krejt adresat që " -"duken si përdorues+foo@përkatësiaime.shembull. Më tej, mund të shtojë aliase " -"te adresa e tij email. Aliase të nevojshëm, të tillë si “postmaster” " -"krijohen automatikisht dhe shpien te i pari përdorues përgjegjës." +"Çdo përdorues në {box_name} merr një adresë email të ngjashme me " +"përdorues@përkatësiaime.shembull. Do të marrë gjithashtu email nga krejt " +"adresat që duken si përdorues+foo@përkatësiaime.shembull. Më tej, mund të " +"shtojë aliase te adresa e tij email. Aliase të nevojshëm, të tillë si " +"“postmaster” krijohen automatikisht dhe shpien te i pari përdorues " +"përgjegjës." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2032,7 +2026,7 @@ msgstr "" "Aplikacioni Roundcube furnizon " "ndërfaqe web për përdoruesit për të përdorur email-in." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2160,7 +2154,7 @@ msgstr "Portë" msgid "Host/Target/Value" msgstr "Strehë/Objektiv/Vlerë" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2171,7 +2165,7 @@ msgstr "" "në rrjet te {box_name} juaj. Mbajta e një firewall-i të aktivizuar dhe të " "formësuar si duhet ul rrezikun e kërcënimeve të sigurisë nga Interneti." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Firewall" @@ -2191,53 +2185,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Portë {name} ({details}) jo e përdorshme për rrjete të brendshëm" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Demoni i firewall-it s’është vënën në punë. Ju lutemi, vëreni në punë. " -"Firewall-i vjen i aktivizuar, si parazgjedhje, në %(box_name)s. Në çfarëdo " -"sistemi me bazë Debian (si edhe %(box_name)s) mund ta vini në punë duke " -"përdorur urdhrin “service firewalld start”, ose, në rast të një sistemi me " -"systemd, me “systemctl start firewalld”." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Shërbim/Portë" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "E aktivizuar" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "E çaktivizuar" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "E lejuar" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "E lejuar (vetëm së brendshmi)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "E lejuar (vetëm së jashtmi)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "E bllokuar" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2247,13 +2227,13 @@ msgstr "" "ky lejohet edhe te firewall-i, dhe kur e çaktivizoni, çaktivizohet " "gjithashtu edhe te firewall-i." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Të thelluara" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2307,7 +2287,7 @@ msgstr "Nis Ujdisjen" msgid "Setup Complete" msgstr "Ujdisje e Plotësuar" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2325,7 +2305,7 @@ msgstr "" "rreshti urdhrash ose përmes klientësh të shumta grafikë të gatshëm. Dhe mund " "ta ndani kodin tuaj me njerëz anembanë botës." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2333,67 +2313,67 @@ msgstr "" "Për të mësuar më tepër se si të përdoret Git, vizitoni përkujdesore Git-i." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Hyrje për shkrim-lexim në depo Git" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Strehim i Thjeshtë Git" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "URL e pavlefshme depoje." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Emër i pavlefshëm depoje." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "Emër i një depoje të re, ose URL për të importuar një depo ekzistuese." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Përshkrim i depos" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Opsionale, për shfaqje në Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Emër të zoti depoje" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Depo private" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Në këtë depo mund të hyjnë vetëm përdorues të autorizuar." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Ka tashmë një depo me këtë emër." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Emër i depos" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "Një varg alfanumerik që identifikon në mënyrë unike një depo." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Degë parazgjedhje" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb e shfaq këtë si një degë parazgjedhje." @@ -2437,19 +2417,19 @@ msgstr "Fshi Depon Git %(name)s" msgid "Delete this repository permanently?" msgstr "Të fshihet kjo depo përgjithmonë?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Depoja u krijua." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Ndodhi një gabim teksa krijohej depoja." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Depoja u përpunua." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Përpunoni depon" @@ -2816,7 +2796,7 @@ msgstr "Mbi {box_name}" msgid "{box_name} Manual" msgstr "Doracak për {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2828,7 +2808,7 @@ msgstr "" "dërguar trafik të fshehtëzuar, përmes një rrjeti të mbajtur në këmbë nga " "vullnetarë, të shpërndarë anembanë botës." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2836,26 +2816,26 @@ msgstr "" "Më më tepër informacion rreth I2P-së mund të gjeni që nga faqja hyrëse e vetë projektit." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" "Vizita e parë te ndërfaqja web e dhënë do të fillojë procesin e formësimit." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Administroni aplikacion I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Rrjet Anonimiteti" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "Ndërmjetës I2P" @@ -2901,7 +2881,7 @@ msgstr "" "një rrjet “peer-to-peer”. Shkarkoni kartela duke shtuar rrëkeza, ose krijoni " "një rrëkezë të re për të ndarë një kartelë me të tjerët." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2911,7 +2891,7 @@ msgstr "" "markup-i të lehta, përfshi Markdown, dhe funksione të rëndomtë blogimi, bie " "fjala, komente dhe prurje RSS." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2925,15 +2905,15 @@ msgstr "" "ekzistueset. Te Formësim Përdoruesish mund të " "ndryshoni këto leje ose të shtoni përdorues të rinj." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki dhe Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Shihni dhe përpunoni aplikacione wiki" @@ -2989,43 +2969,43 @@ msgstr "" "Ky veprim do të heqë krejt postimet, faqet dhe komentet, përfshi historik " "rishikimesh. Të fshihet përgjithmonë kjo wiki ose ky blog?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "U krijua wiki {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "S’u krijua dot wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "U krijua blogu {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "S’u krijua dot blogu: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} u fshi." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "S’u fshi dot {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" "infinoted është një shërbyes për Gobby, një përpunues tekstesh në " "bashkëpunim." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3036,11 +3016,11 @@ msgstr "" "klientin desktop, dhe instalojeni. Mandej nisni Gobby-n dhe përzgjidhni " "“Lidhu me Shërbyes” dhe jepni emrin e përkatësisë së {box_name} tuaj." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Shërbyes Gobby" @@ -3090,7 +3070,7 @@ msgstr "Janus Video Room" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Hollësi licence JavaScript" @@ -3110,7 +3090,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Klient Fjalosjesh" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3125,7 +3105,7 @@ msgstr "" "përkatësi të pranishme. Këtë e bën duke dëshmuar për veten se është i zoti " "i një përkatësie nga Let’s Encrypt, një autoritet dëshmish (AD)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3138,15 +3118,15 @@ msgstr "" "pajtohuni me Marrëveshje " "Pajtimtari Let’s Encrypt before using this service." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Dëshmi" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "S’mund të testojë: S’ka përkatësi të formësuara." @@ -3211,7 +3191,7 @@ msgstr "" "S’ka përkatësi të formësuara. Formësoni " "përkatësi, që të jetë në gjendje të marrë dëshmi për to." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3220,34 +3200,34 @@ msgstr "" "Dëshmi e shfuqizuar me sukses për përkatësinë {domain}.Kjo mund të dojë ca " "çaste të hyjë në fuqi." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "S’u arrit të shfuqizohet dëshmi për përkatësinë {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Dëshmi e marrë me sukses për përkatësinë {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "S’u arrit të merret dëshmi për përkatësinë {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Dëshmi e fshirë me sukses për përkatësinë {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "S’u arrit të fshihet dëshmi për përkatësinë {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3264,7 +3244,7 @@ msgstr "" "funksionojë. Përmes federimi, përdoruesit në një shërbyes të dhënë Matrix " "mund të bisedojnë me përdorues në krejt shërbyesit e tjerë Matrix." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3274,7 +3254,7 @@ msgstr "" "aplikacionin Coturn, ose formësoni një shërbyes " "të jashtëm." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3382,7 +3362,7 @@ msgstr "" "Ju lutemi, kaloni te Let's Encrypt, që " "të merrni një të tillë." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3395,7 +3375,7 @@ msgstr "" "strehuar sajt të llojit wiki, për të mbajtur shënime ose për të bashkëpunuar " "me shokë në projekte." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3410,7 +3390,7 @@ msgstr "" "href=\"/mediawiki/index.php/Special:CreateAccount\">Special:CreateAccount." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3418,12 +3398,12 @@ msgstr "" "Cilido me një lidhje për te kjo wiki mund ta lexojë atë. Ndryshime te lënda " "mund të bëjnë vetëm përdorues që kanë bërë hyrjen në llogaritë e tyre." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3508,35 +3488,35 @@ msgstr "" "Përditësimi i fjalëkalimit dështoi. Ju lutemi, zgjidhni një fjalëkalim më të " "fortë" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Regjistrimet publike u aktivizuan" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Regjistrimet publike u çaktivizuan" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Mënyra private u aktivizua" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Mënyra private u çaktivizua" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Lëkurçja parazgjedhje u ndryshua" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Emri i përkatësisë u përditësua" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Emri i sajtit u përditësua" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3550,11 +3530,11 @@ msgstr "" "lypset një klient Minetest." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Bankëprovë Blloqesh" @@ -3607,7 +3587,7 @@ msgstr "" msgid "Address" msgstr "Adresë" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3793,7 +3773,7 @@ msgstr "Shell i Sigurt" msgid "Services" msgstr "Shërbime" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3801,7 +3781,7 @@ msgstr "" "Formësoni pajisje rrjeti. Lidhuni në Internet përmes Ethernet-i, Wi-Fi ose " "PPPoE. Ndajeni atë lidhje me pajisje të tjera në rrjet." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3809,7 +3789,7 @@ msgstr "" "Pajisjet e administruara përmes metodash të tjera mund të mos jenë të " "pranishme për formësim këtu." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Rrjete" @@ -4244,7 +4224,7 @@ msgstr "Përpunoni lidhjen" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Përpunoni" @@ -4349,7 +4329,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Metodë" @@ -4365,7 +4345,7 @@ msgstr "Shërbyes DNS" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Gjendje" @@ -4378,7 +4358,7 @@ msgid "This connection is not active." msgstr "Kjo lidhje s’është aktive." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Siguri" @@ -4965,7 +4945,7 @@ msgstr "Lidhja {name} u fshi." msgid "Failed to delete connection: Connection not found." msgstr "S’u arrit të fshihet lidhje: S’u gjet lidhje." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4982,20 +4962,20 @@ msgstr "" "brendshme të dhëna nga {box_name}. Mund të hyni edhe në Internet përmes " "{box_name}-it, për më tepër siguri dhe anonimitet." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Lidhuni me shërbime VPN" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Rrjet Virtual Privat" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -5006,58 +4986,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Migroje në ECC" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Instalimi juaj OpenVPN aktualisht përdor RSA. Kalimi nën Kriptografinë " -"moderne Kurbash Eliptike përmirëson shpejtësinë e vendosjes së një lidhjeje " -"dhe sigurinë. Ky veprim është i pakthyeshëm. Në shumicën e kompjuterave " -"njëskedësh ha vetëm pak minuta." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Krejt instalimet e reja të OpenVPN në %(box_name)s do të përdorin KKE (ECC), " -"si parazgjedhje. Rekomandojmë migrim sa më shpejt të jetë e mundur." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Kujdes: Profile klientësh ekzistues do të bëhen të pavlefshme nga ky " -"veprim. Krejt përdoruesit OpenVPN te %(box_name)s duhet të shkarkojnë " -"profilet e tyre të rinj. Për t’u lidhur me këtë shërbyes, duhen përdorur " -"klientë OpenVPN të përputhshëm me KKE (ECC)." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Migroje" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "Për t’u lidhur me VPN-në e %(box_name)s-it, duhet të shkarkoni një profil " @@ -5065,18 +5008,19 @@ msgstr "" "desktop. Ka klientë OpenVPN për shumicën e platformave. Për klientë të " "rekomanduar dhe udhëzime se si të formësohen ata, klikoni “Mësoni më tepër…”." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Profili është specifik për çdo përdorues të %(box_name)s. Mbajeni të " "fshehtë." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Shkarko profilin tim" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5089,19 +5033,19 @@ msgstr "" "{box_name}-it tuaj janë të pakapshme nga pjesa tjetër e Internetit. Kjo " "përfshin gjendjet vijuese:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} gjendet pas një firewall-i të kufizuar." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} është i lidhur te një rrugëzues (pa fill), të cilin nuk e " "kontrolloni ju." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5109,7 +5053,7 @@ msgstr "" "ISP-ja juaj s’ju furnizon një adresë IP të jashtme dhe në vend të kësaj ju " "jep lidhje Internet përmes NAT-i." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5117,11 +5061,11 @@ msgstr "" "ISP-ja juaj s’ju furnizon një adresë IP statike dhe adresa juaj IP ndryshon " "sa herë që lidheni në Internet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "ISP-ja juaj kufizon lidhjet ardhëse." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5136,23 +5080,23 @@ msgstr "" "të ardhmen mund të jetë e mundshme të përdorni {box_name}-in e një shokut " "tuaj për këtë." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "E dukshme Publikisht" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "Përkatësi PageKite" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Përkatësi shërbyesi" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5160,32 +5104,32 @@ msgstr "" "Përzgjidhni shërbyesin tuaj <em>pagekite</em>. Vëreni si " "“pagekite.net”, që të përdorni shërbyesin parazgjedhje pagekite.net." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Portë shërbyesi" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" "Portë e shërbyesit tuaj <em>pagekite</em> (parazgjedhje: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Emër Kite-i" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Shembull: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Emër <em>pagekite</em> i pavlefshëm" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "E fshehtë Kite-i" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5194,35 +5138,35 @@ msgstr "" "fshehta parazgjedhje për llogarinë tuaj, nëse te <em>pagekite</" "em>-i s’është caktuar e fshehtë." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protokoll" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "portë e jashtme (frontend)" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "portë e brendshme (freedombox)" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Aktivizo Nënpërkatësi" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "U fshi shërbimin vetjak" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Ky shërbimi është tashmë i gatshëm si shërbim standard." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "U shtua shërbim vetjak" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Ka tashmë një shërbim të tillë" @@ -5260,29 +5204,29 @@ msgstr "" "përcaktoni këtu. Për shembull, HTTPS në porta të tjera nga 443 dihet se " "shkakton probleme." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Shërbyes (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Sajti do të gjendet në http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Shërbyes (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Sajti do të gjendet në https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Shell i Sigurt (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5334,8 +5278,8 @@ msgstr "" "Aktualisht po xhiron një instalim ose përmirësim. Shihni mundësinë e " "pritjes, deri sa të përfundohet, përpara fikjes apo rinisjes." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Rinise" @@ -5385,6 +5329,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Fike Tani" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5426,7 +5403,7 @@ msgstr "Ndërmjetës Web" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Hapni {url} me ndërmjetësin {proxy} në tcp{kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5443,7 +5420,7 @@ msgstr "" "në linjë dhe një ose më tepër klientë Quassel prej një desktopi ose celulari " "mund të përdoren për t’u lidhur dhe shkëputur prej tij." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your desktopi dhe celulari juaj." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "Klient IRC" @@ -5467,7 +5444,7 @@ msgstr "Klient IRC" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5483,7 +5460,7 @@ msgstr "" "Radicale mund të hyhet nga cilido përdorues me kredenciale hyrjeje në " "{box_name}." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5493,12 +5470,12 @@ msgstr "" "të ri dhe librash adresash. Nuk mbulon shtim veprimtarish ose kontaktesh, " "çka duhen bërë duke përdorur një tjetër klient." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Kalendar dhe Libër adresash" @@ -5572,7 +5549,7 @@ msgstr "" "e_freedombox-it.tuaj>) dhe emrin tuaj të përdoruesit. Klikimi mbi butonin " "e kërkimit do të shfaqë kalendarët dhe librat ekzistues të adresave." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Formësimi i të drejtave për hyrje u përditësua" @@ -5649,8 +5626,8 @@ msgid "" "When enabled, RSS-Bridge can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"Kur aktivizohet, RSS-Bridge mund të përdoret nga cilido përdorues pjesë e grupit të leximit të prurjeve." +"Kur aktivizohet, RSS-Bridge mund të përdoret nga cilido përdorues pjesë e grupit të leximit të prurjeve." #: plinth/modules/rssbridge/__init__.py:27 #, python-brace-format @@ -5663,7 +5640,7 @@ msgstr "" "për të ndjekur sajte të ndryshëm. Kur shtohet një prurje, aktivizoni " "mirëfilltësimin dhe përdorni kredencialet tuaj për {box_name}." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Lexoni dhe pajtohuni te prurje lajmesh" @@ -5676,7 +5653,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "Prodhues Prurjesh RSS" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5684,7 +5661,7 @@ msgstr "" "Samba lejon të ndani me të tjerë kartela dhe dosje mes FreedomBox-it dhe " "kompjuterave të tjerë në rrjetin tuaj vendor." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5698,11 +5675,11 @@ msgstr "" "{hostname}.local (në Linux dhe Mac). Ka tre lloje ndarjesh nga mund të " "zgjidhni " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Pjesë e hapët - e përdorshme nga cilido në rrjetin tuaj vendor." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5710,7 +5687,7 @@ msgstr "" "Pjesë grupi - e përdorshme vetëm nga përdorues të FreedomBox-it të cilët " "janë pjesë e grupit freedombox-share." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5718,15 +5695,15 @@ msgstr "" "Pjesë Home - cilido përdorues në grupin freedombox-share mund të ketë " "hapësirën e vet private." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Hyrje te ndarje private" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Depozitë Kartelash Në Rrjet" @@ -5814,15 +5791,15 @@ msgstr "Emër pjese" msgid "Action" msgstr "Veprim" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "Disk FreedomBox OS" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Pjesë e Hapët" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Pjesë Grupi" @@ -5848,7 +5825,7 @@ msgstr "Pjesa u çaktivizua." msgid "Error disabling share: {error_message}" msgstr "Gabim teksa çaktivizohej pjesë: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5856,7 +5833,7 @@ msgstr "" "Searx është një motor tejkërkimesh Internet që respekton privatësinë. " "Grumbullon dhe shfaq përfundime prej shumë motorësh kërkimi." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5864,41 +5841,41 @@ msgstr "" "Searx mund të përdoret për të shmangur gjurmim dhe profilizim nga motorë " "kërkimesh. Si parazgjedhje, nuk depoziton cookies." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Kërkoni në internet" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Kërkim në Web" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Kërkim i Parrezik" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Përzgjidhni filtrin familjar parazgjedhje për t’u zbatuar mbi përfundimet e " "kërkimit tuaj." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "I moderuar" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Strikt" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Lejo Hyrje Publike" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "Të lejohet ky aplikacion të përdoret nga cilido që mund ta kapë." @@ -6080,7 +6057,7 @@ msgstr "Faqerojtës" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6090,7 +6067,7 @@ msgstr "" "konceptuar të mbrojë trafikun tuaj Internet. Mund të përdoret për të " "anashkaluar filtrim dhe censurim Interneti." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6103,7 +6080,7 @@ msgstr "" "Pajisjet vendore mund të lidhen te ky ndërmjetës, dhe të dhënat e tyre do të " "fshehtëzohen dhe ndërmjetësohen përmes shërbyesit Shadowsocks." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6112,42 +6089,42 @@ msgstr "" "pajisjen, shfletuesin ose aplikacionin tuaj caktoni http://" "freedombox_address:1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Ndërmjetës SOCKS5" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "E këshilluar" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Shërbyes" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Strehëemër ose adresë IP shërbyesi" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Numër porte shërbyesi" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Fjalëkalim i përdorur për të fshehtëzuar të dhëna. Duhet të përputhet me " "fjalëkalimin e shërbyesit." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Metodë fshehtëzimi. Duhet të përputhet me atë të caktuar te shërbyesi." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6156,15 +6133,15 @@ msgstr "" "Dhënia ju lejon të ndani nëpër internet kartela dhe dosje në {box_name}-in " "tuaj me grupe dhe përdorues të zgjedhur nga ju." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Dhënie" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Emër i pjesës" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6172,29 +6149,29 @@ msgstr "" "Një varg alfanumerik me të vogla, që identifikon në mënyrë unike një pjesë. " "Për shembull: media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Shteg për te pjesa" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" "Shteg në disk për te dosja në këtë shërbyes të cilën doni ta ndani me të " "tjerët." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Pjesë publike" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Bëji kartelat në këtë dosje të passhme për këdo që ka lidhjen." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Grupet e përdoruesve që mund të lexojnë kartela te pjesa:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6202,11 +6179,11 @@ msgstr "" "Përdorues të grupit të përzgjedhur të përdoruesve do të jenë në gjendje të " "lexojnë kartelat te pjesa.." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Ka tashmë një pjesë me këtë emër." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "Pjesët duhet të jenë ose publike, ose të ndara me të paktën një grup" @@ -6243,19 +6220,19 @@ msgstr "U shtua pjesë." msgid "Add Share" msgstr "Shtoni Pjesë" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "U përpunua pjesa." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Përpunoni Pjesë" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Pjesa u fshi." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6265,7 +6242,7 @@ msgstr "" "kartelash. Këto mund të përdoren për të kthyer sistemin te një gjendje e " "mëparshme e njohur si e mirë, në rast ndryshimesh të padëshiruar te sistemi." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6276,7 +6253,7 @@ msgstr "" "dhe gjithashtu para dhe pas instalimit të një software-i. Fotografimet e " "vjetra do të spastrohen automatikisht, në përputhje me rregullimet më poshtë." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for kopjeruajtjet, ngaqë mund të rikthehen vetëm në të " "njëjtën pjesë. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Depozito Fotografime" @@ -6390,7 +6367,7 @@ msgstr "Datë" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Fshi Fotografime" @@ -6444,58 +6421,58 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Prapaktheje te Fotografimi #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "krijuar dorazi" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "rrjedhë kohore" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Administroni Fotografime" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "U krijua fotografim." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "U përditësua formësim për depozitim fotografimesh" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Gabim veprimi: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "U fshinë fotografimet e përzgjedhur" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" "Fotografimi është aktualisht në përdorim. Ju lutemi, riprovoni më vonë." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "U kthye prapa te fotografimi #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Që të plotësohet prapakthimi, duhet rinisur sistemi." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Prapaktheje te Fotografim" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6507,7 +6484,7 @@ msgstr "" "një kompjuter i largët i autorizuar mund të kryejë punë administrimi, të " "kopjojë kartela ose të xhirojë shërbime të tjera." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Shërbyes Shelli të Sigurt (SSH)" @@ -6545,14 +6522,6 @@ msgstr "Algoritëm" msgid "Fingerprint" msgstr "Shenja gishtash" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "Mirëfilltësimi SSH me fjalëkalim u çaktivizua." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "Mirëfilltësimi SSH me fjalëkalim u aktivizua." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Hyrje Njëshe" @@ -6565,7 +6534,7 @@ msgstr "Hyrje" msgid "Logged out successfully." msgstr "U dol me sukses." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6577,107 +6546,107 @@ msgstr "" "përdorim, të montoni dhe çmontoni media të heqshme, të zgjeroni pjesën " "rrënjë, etj." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Depozitë" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bajte" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Veprimi dështoi." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Veprimi u anulua." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Pajisja po çmontohet tashmë." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" "Veprimi nuk mbulohet, për shkak se mungon mbulimi për përudhësin/mjetin." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Veprimit i mbaroi koha." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "Veprimi do të zgjonte një disk që është në gjendjen “deep-sleep”." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Po përpiqet të çmontohet një pajisje që është e zënë." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Veprimi është anuluar tashmë." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "I paautorizuar për kryerjen e veprimit të kërkuar." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Pajisja është e çmontuar tashmë." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Pajisja s’është e montuar." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "S’i lejohet të përdorë mundësinë e kërkuar." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Pajisja është montuar nga tjetër përdorues." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Hapësirë e ulët në pjesë sistemi: {percent_used}% të përdorura, {free_space} " "të lira." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Hapësirë disku e pamjaftueshme" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Shumë afër dështimi disku" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6686,39 +6655,39 @@ msgstr "" "Disku {id} po raporton se ka gjasa të dështojë tani afër. Kopjoni çfarëdo të " "dhënash që mundeni ende dhe zëvendësoni diskun." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Listë e pavlefshme emrash." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Drejtoria s’ekziston." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Shtegu s’është drejtori." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Drejtoria s’është e lexueshme nga përdoruesi." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Drejtoria s’është e shkrueshme nga përdoruesi." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Drejtori" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Nëndrejtori (opsionale)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Drejtori tjetër (jepeni më poshtë)" @@ -6755,7 +6724,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Zgjero Pjesën Rrënjë" @@ -6778,30 +6747,30 @@ msgstr "" "veprimi, në pjesën tuaj rrënjë do të ketë %(expandable_root_size)s hapësirë " "shtesë të lirë." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Gabim në zgjerim pjese: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Pjesa u zgjerua me sukses." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} mund të hiqet pa rrezik." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Pajisja mund të hiqet pa rrezik." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Gabim në nxjerrje pajisjeje: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6813,7 +6782,7 @@ msgstr "" "ndryshimi, ose fshirja e kartelave në një pajisje do të përsëritet vetvetiu " "në krejt pajisjet e tjera që xhirojnë gjithashtu Syncthing-un." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6832,20 +6801,20 @@ msgstr "" "Ndërfaqja web te {box_name} është e përdorshme vetëm nga përdorues që i " "përkasin grupit “përgjegjës”, ose atij “syncthing-access”." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Administroni aplikacionin Syncthing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Njëkohësim Kartelash" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6859,7 +6828,7 @@ msgstr "" "përdorni Shfletuesin Tor." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6868,40 +6837,40 @@ msgstr "" "Një portë SOCKS Tor-i për rrjete të brendshëm në {box_name} tuaj gjendet në " "portën TCP 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Shërbim Onion Tor" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Ndërmjetës SOCKS Tor" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Rele Ure Tor" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Portë releje Tor e gatshme" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "U regjistruar transport Obfs3" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "U regjistruar transport Obfs3" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "URL hyrjesh {url} në tcp{kind} përmes Tor-i" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Ripohoni përdorim Tor-i te {url} në tcp{kind}" @@ -7023,11 +6992,11 @@ msgstr "Shërbim Onion" msgid "Ports" msgstr "Porta" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Po përditësohet formësimi" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Gabim në formësimin e aplikacionit: {error}" @@ -7085,7 +7054,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7095,16 +7064,17 @@ msgstr "" "i konceptuar të lejojë lexim lajmesh prej çfarëdo vendndodhjeje, ndërkohë që " "duket si një aplikacion desktop, aq afër kësaj sa mundet." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -"Kur aktivizohet, Tiny Tiny RSS mund të përdoret nga cilido përdorues pjesëtar i grupit të leximit të prurjeve." +"Kur aktivizohet, Tiny Tiny RSS mund të përdoret nga cilido përdorues pjesëtar i grupit të leximit të " +"prurjeve." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7113,11 +7083,11 @@ msgstr "" "dekstop, përdorni URL /tt-rss-app për t’u " "lidhur." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Lexues Prurjesh Lajmesh" @@ -7125,13 +7095,13 @@ msgstr "Lexues Prurjesh Lajmesh" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Kontrolloni dhe aplikoni përditësimet më të reja software-i dhe sigurie." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7144,22 +7114,22 @@ msgstr "" "rinisja e sistemit shihet si e domosdoshme, bëhet automatikisht më 02:00, " "duke bërë që krejt aplikacionet të jenë jashtë funksionimi për ca çaste." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Përditësim Software-i" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox-i u Përditësua" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "S’u fillua dot përditësim shpërndarjeje" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7170,11 +7140,11 @@ msgstr "" "Përditësimi i shpërndarjes do të riprovohet pas 24 orësh, nëse kjo është " "aktivizuar." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Përditësimi i shpërndarjes filloi" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7354,45 +7324,45 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" "Gabim teksa formësohej <em>unattended-upgrades</em>: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "U aktivizuan përmirësime të automatizuara" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Përmirësimet e vetvetishme janë çaktivizuar" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Me përmirësim shpërndarjeje të aktivizuar" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Me përmirësim shpërndarjeje të çaktivizuar" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Procesi i përmirësimit filloi." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Nisja e përmirësimi dështoi." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Përditësime të shpeshta veçorish të aktivizuara." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Po fillohet provë përmirësimi shpërndarjeje." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7403,7 +7373,7 @@ msgstr "" "aplikacione kërkojnë doemos një llogari përdoruesi, për të qenë pjesë e një " "grupi që autorizon përdoruesin të përdorë aplikacionin." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7415,15 +7385,15 @@ msgstr "" "vetëm përdoruesit e grupit përgjegjës mund të ndryshojnë " "aplikacionet, apo rregullimet e sistemit." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Përdorues dhe Grupe" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Hyrje te krejt shërbimet dhe rregullime të sistemit" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Kontrolloni zërin LDAP \"{search_item}\"" @@ -7443,11 +7413,11 @@ msgstr "" "E domosdoshme. 150 ose më pak shenja. Vetëm shkronja anglishteje, shifra, " "dhe @/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Fjalëkalim Autorizimi" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7455,11 +7425,11 @@ msgstr "" "Jepni fjalëkalimin për përdoruesin “{user}”, që të autorizoni ndryshime " "llogarie." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Fjalëkalim i pavlefshëm." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7474,12 +7444,12 @@ msgstr "" "në krejt shërbimet. Munden edhe të hyjnë në sistem përmes SSH-së dhe të kenë " "privilegje administrative (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "S’u arrit të krijohej përdorues LDAP: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "S’u arrit të shtohej përdorues i ri te grupi {group}: {error}" @@ -7499,41 +7469,41 @@ msgstr "" "një për rresht. Rreshta të zbrazët dhe rreshta që fillojnë me # do të " "shpërfillen." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Riemërtimi i përdoruesit LDAP dështoi." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "S’u arrit të hiqej përdorues nga grupi." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "S’u arrit të shtohej përdorues te grup." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "S’arrihet të ujdisen kyçe SSH." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "S’u arrit të ndryshohej gjendje përdoruesi." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Ndryshimi i fjalëkalimit për përdorues LDAP dështoi." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "S’u arrit të shtohej përdorues i ri te grupi i përgjegjësve: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "S’u arrit të kufizohej hyrja në konsol: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Llogaria e përdoruesit u krijua, tani jeni i futur në llogari" @@ -7550,12 +7520,12 @@ msgstr "Ruaje Fjalëkalimin" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Krijoni Përdorues" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Fshi Përdorues" @@ -7597,13 +7567,19 @@ msgid "The following administrator accounts exist in the system." msgstr "Në sistem ekzistojnë llogaritë vijuese përgjegjësish." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Fshijini këto llogari që nga rreshti i urdhrave dhe rifreskoni faqen, që të " "krijohet një llogari e cila të jetë e përdorushme me %(box_name)s. Te " @@ -7612,7 +7588,7 @@ msgstr "" "përdorshme me %(box_name)s, anashkalojeni këtë hap." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Përdorues" @@ -7645,34 +7621,34 @@ msgstr "" msgid "Save Changes" msgstr "Ruaji Ndryshimet" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Përdoruesi %(username)s u krijua." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Përdoruesi %(username)s u përditësua." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Përpunoni Përdorues" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Përdoruesi {user} u fshi." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Fshirja e përdoruesi LDAP dështoi." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Ndryshoni Fjalëkalimin" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Fjalëkalimi u ndryshua me sukses." @@ -8010,7 +7986,7 @@ msgstr "Fshije Lidhjen me Shërbyesin" msgid "Server deleted." msgstr "Shërbyesi u fshi." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -8024,7 +8000,7 @@ msgstr "" "zgjidhet përmes përdorimit të temave. Ndërfaqja e administrimit dhe faqet " "web të prodhuara janë të përshtatshme për pajisje celulare." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -8037,7 +8013,7 @@ msgstr "" "{box_name} me emrin e saktë të përkatësisë. Aktivizoni permalidhje te " "ndërfaqja e përgjegjësit, për URL më të mira për te faqet dhe postimet tuaja." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8048,7 +8024,7 @@ msgstr "" "\">faqen e përgjegjësit, që të mund të përdorni ndërfaqen e përgjegjësit " "në të ardhmen." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8059,12 +8035,12 @@ msgstr "" "ose tema shtesë mund të instalohet dhe përmirësohen duke e marrë ju përsipër " "rrezikun." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Sajt dhe Blog" @@ -8081,7 +8057,7 @@ msgstr "" "sajtin ose blogun WordPress. Aktivizojeni vetëm pasi të jetë kryer ujdisja " "fillestare e WordPress-it." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8103,7 +8079,7 @@ msgstr "" "pamjet hartë dhe kalendar. Foto individuale mund të ndahen me të tjerë duke " "dërguar një lidhje të drejtpërdrejtë." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8114,11 +8090,11 @@ msgstr "" "Zoph. Për përdorues të tjerë, llogaritë mund të krijohen si në {box_name}, " "ashtu edhe në Zoph, me të njëjtin emër përdoruesi." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Sistemues Fotografish" @@ -8171,97 +8147,93 @@ msgstr "Po pritet të fillohet: {name}" msgid "Finished: {name}" msgstr "Përfundoi: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Paketa {expression} s’është e gatshme për instalim" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" "Paketa {package_name} gjendet nën versionin më të ri ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Gabim në xhirimin e urdhrit apt-get" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "po instalohet" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "po shkarkohet" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "ndryshim media" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "kartelë formësimi: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Mbaroi koha teksa pritej për përgjegjës paketash" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Po instalohet aplikacioni" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Po përditësohet aplikacioni" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Gabim në instalimin e aplikacionit: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Gabim në përditësimin e aplikacionit: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Gabim në instalimin e aplikacionit: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Gabim në përditësimin e aplikacionit: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "Aplikacioni u instalua." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Aplikacioni u përditësua" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Po çinstalohet aplikacion" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Gabim në çinstalimin e aplikacionit: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Gabim në çinstalimin e aplikacionit: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "Aplikacioni u çinstalua." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Po përditësohet paketa aplikacioni" @@ -8320,53 +8292,54 @@ msgstr "Instalim" msgid "Service %(service_name)s is not running." msgstr "Shërbimi %(service_name)s s’po xhiron." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Funksione bazë dhe ndërfaqe web për %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Kreu" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Kreu" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Aplikacione" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Aplikacione" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Sistem" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Sistem" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Ndryshoni fjalëkalimin" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Fike" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Dil" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Përzgjidhni gjuhën" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Hyni" @@ -8655,6 +8628,75 @@ msgstr "para çinstalimit të {app_id}" msgid "Gujarati" msgstr "Gujaratase" +#~ msgid "Enable DNSSEC" +#~ msgstr "Aktivizo DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Aktivizo Zgjerime Sigurie Sistemi Emrash Shërbyesish" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Demoni i firewall-it s’është vënën në punë. Ju lutemi, vëreni në punë. " +#~ "Firewall-i vjen i aktivizuar, si parazgjedhje, në %(box_name)s. Në " +#~ "çfarëdo sistemi me bazë Debian (si edhe %(box_name)s) mund ta vini në " +#~ "punë duke përdorur urdhrin “service firewalld start”, ose, në rast të një " +#~ "sistemi me systemd, me “systemctl start firewalld”." + +#~ msgid "Migrate to ECC" +#~ msgstr "Migroje në ECC" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Instalimi juaj OpenVPN aktualisht përdor RSA. Kalimi nën Kriptografinë " +#~ "moderne Kurbash Eliptike përmirëson shpejtësinë e vendosjes së një " +#~ "lidhjeje dhe sigurinë. Ky veprim është i pakthyeshëm. Në shumicën e " +#~ "kompjuterave njëskedësh ha vetëm pak minuta." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Krejt instalimet e reja të OpenVPN në %(box_name)s do të përdorin KKE " +#~ "(ECC), si parazgjedhje. Rekomandojmë migrim sa më shpejt të jetë e mundur." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Kujdes: Profile klientësh ekzistues do të bëhen të pavlefshme nga " +#~ "ky veprim. Krejt përdoruesit OpenVPN te %(box_name)s duhet të shkarkojnë " +#~ "profilet e tyre të rinj. Për t’u lidhur me këtë shërbyes, duhen përdorur " +#~ "klientë OpenVPN të përputhshëm me KKE (ECC)." + +#~ msgid "Migrate" +#~ msgstr "Migroje" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "Mirëfilltësimi SSH me fjalëkalim u çaktivizua." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Mirëfilltësimi SSH me fjalëkalim u aktivizua." + +#~ msgid "Error running apt-get" +#~ msgstr "Gabim në xhirimin e urdhrit apt-get" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Funksione bazë dhe ndërfaqe web për %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Lidhje Rrjeti" diff --git a/plinth/locale/sr/LC_MESSAGES/django.po b/plinth/locale/sr/LC_MESSAGES/django.po index 0b396a9a7..d40ea111c 100644 --- a/plinth/locale/sr/LC_MESSAGES/django.po +++ b/plinth/locale/sr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:20+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Serbian calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1095,22 +1088,22 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 #, fuzzy #| msgid "Archive created." msgid "Library created." msgstr "Arhiva kreirana." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1153,24 +1146,24 @@ msgstr "Kokpit" msgid "Server Administration" msgstr "Administracija Servera" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1266,47 +1259,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1314,7 +1307,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1544,11 +1537,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1660,7 +1653,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1721,13 +1714,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1851,14 +1844,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1866,7 +1859,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1876,13 +1869,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2011,7 +2004,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2019,7 +2012,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -2039,61 +2032,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2139,7 +2123,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2150,73 +2134,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2260,19 +2244,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2565,7 +2549,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2573,31 +2557,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Proxy" @@ -2634,14 +2618,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2650,15 +2634,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2712,41 +2696,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2754,11 +2738,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2804,7 +2788,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2822,7 +2806,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2832,7 +2816,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2840,15 +2824,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2911,41 +2895,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2955,14 +2939,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3043,7 +3027,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3051,7 +3035,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3060,18 +3044,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3142,39 +3126,39 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain Name Server" msgid "Domain name updated" msgstr "Domain Name Server" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain Name Server" msgid "Site name updated" msgstr "Domain Name Server" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3183,11 +3167,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3232,7 +3216,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3393,19 +3377,19 @@ msgstr "" msgid "Services" msgstr "Služi" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3751,7 +3735,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3856,7 +3840,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3872,7 +3856,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3885,7 +3869,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4429,7 +4413,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4440,20 +4424,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4463,61 +4447,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4526,33 +4478,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4561,87 +4513,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4675,29 +4627,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4739,8 +4691,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4782,6 +4734,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4813,7 +4796,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4824,7 +4807,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4844,7 +4827,7 @@ msgstr "" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4854,19 +4837,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4927,7 +4910,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4999,7 +4982,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5012,13 +4995,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5027,31 +5010,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5129,17 +5112,17 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 #, fuzzy #| msgid "FreedomBox" msgid "FreedomBox OS disk" msgstr "KutijaSlobode" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5165,51 +5148,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5362,14 +5345,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5378,97 +5361,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5505,26 +5488,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5532,14 +5515,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5633,7 +5616,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5681,59 +5664,59 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 #, fuzzy #| msgid "Archive created." msgid "manually created" msgstr "Arhiva kreirana." -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5741,7 +5724,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5774,14 +5757,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5794,7 +5769,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5802,143 +5777,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5972,7 +5947,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5990,30 +5965,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6021,7 +5996,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6033,20 +6008,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6055,47 +6030,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6193,13 +6168,13 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "Configuration updated" msgid "Updating configuration" msgstr "Konfiguracija sačuvana" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6257,14 +6232,14 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "It can be accessed by any user on {box_name} " @@ -6276,17 +6251,17 @@ msgstr "" "Pristup moguć korisnik na {box_name} koja " "pripada admin grupi." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6294,12 +6269,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6307,33 +6282,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6481,51 +6456,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6533,15 +6508,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6559,21 +6534,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6582,12 +6557,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6603,41 +6578,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6654,12 +6629,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6697,17 +6672,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6738,34 +6713,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7074,7 +7049,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7083,7 +7058,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7092,26 +7067,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7125,7 +7100,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7138,7 +7113,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7146,11 +7121,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7199,110 +7174,104 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Existing Backups" -msgid "Error running apt-get" -msgstr "Postojeće rezervne kopije" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Greška prilikom instaliranja aplikacije: {string}{details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Greška prilikom instaliranja aplikacije: {string}{details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikacija instalirana." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Greška prilikom instaliranja aplikacije: {string}{details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikacija instalirana." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7353,53 +7322,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -7663,6 +7633,17 @@ msgstr "" msgid "Gujarati" msgstr "" +#~ msgid "Enable DNSSEC" +#~ msgstr "Aktiviraj DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Aktiviraj Domain Name System Security Ekstenziju" + +#, fuzzy +#~| msgid "Existing Backups" +#~ msgid "Error running apt-get" +#~ msgstr "Postojeće rezervne kopije" + #~ msgid "" #~ "Cockpit requires that you access it through a domain name. It will not " #~ "work when accessed using an IP address as part of the URL." diff --git a/plinth/locale/sv/LC_MESSAGES/django.po b/plinth/locale/sv/LC_MESSAGES/django.po index 821e39821..8d28c0321 100644 --- a/plinth/locale/sv/LC_MESSAGES/django.po +++ b/plinth/locale/sv/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-10-03 14:15+0000\n" "Last-Translator: Michael Breidenbach \n" "Language-Team: Swedish calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1045,23 +1038,23 @@ msgstr "" "Endast användare som tillhör calibre -gruppen kan komma åt appen. " "Alla användare med åtkomst kan använda alla bibliotek." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Använd calibre e-bokbibliotek" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "E-bok Bibliotek" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Det nya bibliotekets namn" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1069,7 +1062,7 @@ msgstr "" "Endast bokstäver i det engelska alfabetet, siffror och tecken _ . och - utan " "mellanslag eller specialtecken. Exempel: My_Library_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Ett bibliotek med detta namn finns redan." @@ -1117,20 +1110,20 @@ msgstr "Gå till biblioteket %(library)s" msgid "Delete library %(library)s" msgstr "Ta bort bibliotek %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Bibliotek skapat." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Ett fel uppstod när biblioteket skulle skapas." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} borttagen." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Kunde inte ta bort {name}: {error}" @@ -1178,7 +1171,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Server administrering" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1186,18 +1179,18 @@ msgstr "" "Här kan du ställa in några allmänna konfigurationsalternativ som värdnamn, " "domännamn, webserver, hemsida etc." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Allmän Konfiguration" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Konfigurera" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1310,47 +1303,47 @@ msgstr "" "Loggar innehåller information om vem som har åtkomst till systemet och " "felsökningsinformation från olika tjänster" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Fel inställning av värdnamn: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Värdnamn inställt" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Fel inställning av domännamn: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Domännamn inställt" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Fel vid inställning av webbserverns hemsida: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Webbserverns hemsida är inställt" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Fel vid ändring av avancerat läge: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Visar avancerade appar och funktioner" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Dölja avancerade appar och funktioner" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1362,7 +1355,7 @@ msgstr "" "WebRTC, SIP och andra kommunikationsservrar kan använda den för att upprätta " "ett samtal mellan parter som annars inte kan ansluta till varandra." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse eller ejabberd måste " "konfigureras med de uppgifter som tillhandahålls här." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP-hjälpare" @@ -1435,13 +1428,13 @@ msgstr "Fel i inställning av tidszon: {exception}" msgid "Time zone set" msgstr "Tidszon inställd" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "" "Deluge är en BitTorrentklient som inkluderar ett Webbaserat " "användargränssnitt." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1449,16 +1442,16 @@ msgstr "" "Standardlösenordet är \"deluge\", men du bör logga in och ändra det " "omedelbart efter att du har aktiverat den här tjänsten." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Ladda ner filer med BitTorrent-applikationer" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent Webbklient" @@ -1584,7 +1577,7 @@ msgstr "Resultat" msgid "Diagnostic Test" msgstr "Diagnostiktest" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1595,7 +1588,7 @@ msgstr "" "kan det vara svårt för andra att hitta dig på nätet. Detta förhindrar andra " "att nå de tjänster som tillhandahålls av denna {box_name}." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1612,7 +1605,7 @@ msgstr "" "servern ditt DNS-namn till din nya IP, och om någon från Internet ber om " "ditt DNS-namn, kommer hen att få din aktuella IP som svar." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1625,11 +1618,11 @@ msgstr "" "baserade tjänster på freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Klient för Dynamisk DNS" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Dynamiskt Domännamn" @@ -1757,7 +1750,7 @@ msgstr "Detta fält krävs." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1812,7 +1805,7 @@ msgstr "Servern vägrade anslutning" msgid "Already up-to-date" msgstr "Redan uppdaterad" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1820,7 +1813,7 @@ msgstr "" "XMPP är en öppen och standardiserad kommunikationsprotokoll. Här kan du köra " "din XMPP-server (kallad ejabberd)." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client användare med en {box_name} inloggning." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn eller konfigurera en extern server." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabbert" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Chat-Server" @@ -1969,7 +1962,7 @@ msgstr "" "kommer att se ut som användarnamn@%(domainname)s. Du kan ställa in " "din domän på systemet Konfigurera sidan." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1980,7 +1973,7 @@ msgstr "" "postklienter att komma åt din brevlåda med hjälp av IMAP och POP3. Rspamd " "tar hand om skräppost." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1993,7 +1986,7 @@ msgstr "" "begränsningen efter en uttrycklig begäran. Se manualsidan för mer " "information." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2008,7 +2001,7 @@ msgstr "" "alias som \"postmaster\" skapas automatiskt och pekar på den första " "administratörsanvändaren." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2016,7 +2009,7 @@ msgstr "" "Roundcube app ger användarna " "webbgränssnitt för att komma åt e-post." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2146,7 +2139,7 @@ msgstr "Port" msgid "Host/Target/Value" msgstr "Värd/Mål/Värde" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2157,7 +2150,7 @@ msgstr "" "nätverkstrafiken på din {box_name}. Att ha en brandvägg aktiverad och " "korrekt konfigurerad minskar risken för säkerhetshot från Internet." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Brandvägg" @@ -2177,52 +2170,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port {name} ({details}) är inte tillgängligt för externa nätverk" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Brandväggsdemonen körs inte. Vänligen starta den. Brandväggen är aktiverad " -"som standard på %(box_name)s. På ett Debian-baserade system (till exempel " -"%(box_name)s) Du kan starta den med kommandot \"service firewalld start\", " -"alternativt, vid ett system med systemd \"systemctl start firewalld\"." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Service/Port" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Aktiverad" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Inaktiverad" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Tillåtna" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Tillåtna (endast interna)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Tillåtna (endast externa)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Blockerade" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2232,13 +2212,13 @@ msgstr "" "automatiskt i brandväggen och om du inaktiverar en tjänst, så inaktiveras " "den även automatiskt i brandväggen." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Avancerat" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2291,7 +2271,7 @@ msgstr "Starta installationsprogrammet" msgid "Setup Complete" msgstr "Installationen Klar" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2309,7 +2289,7 @@ msgstr "" "Git-klient eller med flera tillgängliga grafiska klienter. Och du kan dela " "din kod med människor runt om i världen." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2317,68 +2297,68 @@ msgstr "" "För att lära dig mer om hur du använder Git besökGit handledning." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Läs-skrivåtkomst till Git-respositories" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Enkelt Git hosting" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Ogiltigt respository URL." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Ogiltigt respository namn." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Namn på en ny databas eller URL för att importera en befintlig databas." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Beskrivning av förvaret" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Tillval, för att visa på Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Förvarets ägarnamn" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Privat respository" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Tillåt endast behöriga användare att komma åt detta respository." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Ett förvar med det här namnet finns redan." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Förvarets namn" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "En alfanumerisk sträng som identifierar ett respository unikt." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Standardgren" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb visar detta som en standardgren." @@ -2422,19 +2402,19 @@ msgstr "Ta bort Git-respository %(name)s" msgid "Delete this repository permanently?" msgstr "Radera detta arkiv permanent?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Respository skapat." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Ett fel uppstod medan skapa ett repository." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Respository redigerad." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Redigera respository" @@ -2797,7 +2777,7 @@ msgstr "Om {box_name}" msgid "{box_name} Manual" msgstr "{box_name} Manual" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2809,7 +2789,7 @@ msgstr "" "anonymitet genom att skicka krypterad trafik via ett volontärstyrt nätverk " "distribuerat över hela världen." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2817,7 +2797,7 @@ msgstr "" "För att hitta mer information om I2P på deras projekthemsida." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." @@ -2825,19 +2805,19 @@ msgstr "" "Det första besöket i det medföljande webbgränssnittet kommer att initiera " "konfigurationsprocessen." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Hantera I2P appen" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Anonymitetsnätverk" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P proxy" @@ -2882,7 +2862,7 @@ msgstr "" "to-peer-nätverk. Ladda ner filer genom att lägga till torrenter eller skapa " "en ny torrent för att dela en fil." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2892,7 +2872,7 @@ msgstr "" "lightweight pålägg språken, inklusive markdown, och gemensam blogging " "funktionellitet sådan som kommentarerna och RSS feeds." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2905,15 +2885,15 @@ msgstr "" "redigera befindliga. I Användarkonfiguration kan du ändra dessa behörigheter eller lägga till nya användare." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "Ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki och Blogg" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Visa och redigera wiki-applikationer" @@ -2969,41 +2949,41 @@ msgstr "" "Den här åtgärden tar bort alla inlägg, sidor och kommentarer, även " "versionshistorik. Ta bort denna wiki eller blogg permanent?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Skapade wiki {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Kunde inte skapa wiki: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Blogg skapad {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Kunde inte skapa blogg: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} borttagen." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Kunde inte ta bort {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted är en server för Gobby, en kollaborativ textredigerare." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3014,11 +2994,11 @@ msgstr "" ", desktop client och installera det. Starta sedan Gobby och välj " "\"Anslut till server\" och ange ditt {box_name} domännamn." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "Infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby-Server" @@ -3066,7 +3046,7 @@ msgstr "Janus videorum" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "JavaScript-licensinformation" @@ -3086,7 +3066,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Chat klient" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3101,7 +3081,7 @@ msgstr "" "domän. Detta sker genom att den bevisar sig vara ägare till en domän för " "Let's Encrypt, en auktoriserad certifikatutfärdare ." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3113,15 +3093,15 @@ msgstr "" "Läs igenom och acceptera Let's Encrypt användaravtal innan du använder denna tjänst." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Låt oss kryptera" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Certifikaterna" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Kan inte testa: Inga domäner är konfigurerade." @@ -3186,7 +3166,7 @@ msgstr "" "Inga domäner har konfigurerats. Konfigurera " "domäner för att kunna få certifikat för dem." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3195,34 +3175,34 @@ msgstr "" "Certifikatet återkallat för domänen {domain}. Det kan ta några ögonblick att " "träda i kraft." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Det gick inte att återkalla certifikatet för domänen {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Certifikat erhållet för domänen {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Det gick inte att erhålla certifikat för domänen {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Certifikatet framgångsrikt återkallat för domänen {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Det gick inte att ta bort certifikatet för domänen {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3239,7 +3219,7 @@ msgstr "" "fungera. Användare på en given Matrix-server kan samtala med användare på " "alla andra Matrix-servrar via federation." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3248,7 +3228,7 @@ msgstr "" "Matrix Synapse behöver en STUN/TURN-server för ljud-/videosamtal. Installera " "Coturn-appen eller konfigurera en extern server." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3353,7 +3333,7 @@ msgstr "" "certifikat. Gå till Let's Encrypt för " "att få en sådan." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3365,7 +3345,7 @@ msgstr "" "kan använda Media att vara värd för en wiki-liknande webbplats, göra " "anteckningar eller samarbeta med vänner på projekt." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3379,7 +3359,7 @@ msgstr "" "fler användarkonton från MediaWiki själv genom att gå till Special: Skapa konto sida." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3387,12 +3367,12 @@ msgstr "" "Alla som har en länk till denna wiki kan läsa den. Endast användare som är " "inloggade kan göra ändringar i innehållet." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Wiki" @@ -3475,35 +3455,35 @@ msgstr "Lösenord uppdaterad" msgid "Password update failed. Please choose a stronger password" msgstr "Lösenordsuppdateringen misslyckades. Välj ett starkare lösenord" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Offentliga registreringar aktiverade" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Offentliga registreringar avaktiverad" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Privat läge aktiverat" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Privat läge inaktiverat" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Standardskal ändrat" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Domännamnet uppdaterat" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Sidnamnet har uppdaterats" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3516,11 +3496,11 @@ msgstr "" "(30000). För att ansluta till servern, en Minetest klient behövs." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Block sandbox" @@ -3570,7 +3550,7 @@ msgstr "Om inaktiverat kan spelare inte dö eller få skador av något slag." msgid "Address" msgstr "Adress" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3756,7 +3736,7 @@ msgstr "Secure Shell" msgid "Services" msgstr "Tjänster" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3764,7 +3744,7 @@ msgstr "" "Konfigurera nätverksenheter. Anslut till Internet via Ethernet, Wi-Fi eller " "PPPoE. Dela den anslutningen med andra enheter i nätverket." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3772,7 +3752,7 @@ msgstr "" "Enheter som administreras via andra metoder kanske inte är tillgängliga för " "konfiguration här." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Nätverk" @@ -4205,7 +4185,7 @@ msgstr "Redigera anslutning" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Redigera" @@ -4310,7 +4290,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Metod" @@ -4326,7 +4306,7 @@ msgstr "DNS-Server" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Standard" @@ -4339,7 +4319,7 @@ msgid "This connection is not active." msgstr "Den här anslutningen är inte aktiv." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Säkerhet" @@ -4925,7 +4905,7 @@ msgstr "Anslutning {name} borttagen." msgid "Failed to delete connection: Connection not found." msgstr "Det gick inte att ta bort anslutning: Anslutning hittades inte." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4942,20 +4922,20 @@ msgstr "" "tillhandahålls av {box_name}. Du kan också komma åt resten av Internet via " "{box_name} för ökad säkerhet och anonymitet." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Ansluta till VPN-tjänster" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Virtuellt privat nätverk" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4966,58 +4946,21 @@ msgstr "" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "Migrera till ECC" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"Din OpenVPN-installation använder för närvarande RSA. Om du byter till den " -"moderna Elliptic Curve Cryptography förbättrar hastigheten för att upprätta " -"en anslutning och säkerhet. Den här åtgärden är oåterkallelig. Det bör bara " -"ta några minuter på de flesta enda ombord datorer." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"Alla nya installationer av OpenVPN på %(box_name)s kommer att använda ECC " -"som standard. Vi rekommenderar migrering så snart som möjligt." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -" Varning: Befintliga klientprofiler kommer att ogiltigförklaras av " -"den här åtgärden. Alla OpenVPN-användare på %(box_name)s måste hämta sina " -"nya profiler. OpenVPN-klienter som är kompatibla med ECC bör användas för " -"att ansluta till den här servern." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Flytta" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "För att ansluta till %(box_name)s VPN måste du ladda ner en profil och mata " @@ -5026,17 +4969,18 @@ msgstr "" "\" ovan för rekommenderade klienter och instruktioner om hur du konfigurerar " "dem." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" "Profilen är specifik för varje användare av %(box_name)s Håll det hemligt." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Ladda ner min profil" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5049,18 +4993,18 @@ msgstr "" "tjänster inte kan nås från resten av Internet. Detta inkluderar följande " "situationer:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} är bakom en begränsad brandvägg." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} är anslutet till en (trådlös) router som du inte kontrollerar." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5068,7 +5012,7 @@ msgstr "" "Din ISP ger dig inte en extern IP-adress och ger istället Internet " "uppkoppling via NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5076,11 +5020,11 @@ msgstr "" "Din ISP ger dig inte en statisk IP-adress och din IP-adress ändras varje " "gång du ansluter till Internet." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Din ISP begränsar inkommande anslutningar." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5094,23 +5038,23 @@ msgstr "" "pagekite. net . I framtiden kan det vara möjligt att använda din kompis " "{box_name} för detta." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Offentlig Synlighet" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite domän" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Server-domän" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5118,31 +5062,31 @@ msgstr "" "Välj din pagekite-Server. Ange \"pagekite.net\" om du vill använda " "standardservern pagekite.net." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Server Port" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Port på din pagekite Server (standard: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite namn" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Exempel: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Ogiltigt kite-namn" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite hemlighet" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5150,35 +5094,35 @@ msgstr "" "En hemlighet som är associerad med draken eller standard hemligheten för " "ditt konto om ingen hemlighet är inställd på draken." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "Protokollet" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "extern port (frontend)" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "intern port (freedombox)" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Aktivera underdomäner" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Borttagen anpassad tjänst" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Denna tjänst är tillgänglig som standardtjänst." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Lade till anpassad service" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Den här tjänsten finns redan" @@ -5215,33 +5159,33 @@ msgstr "" "de protokoll/port kombinationer som du kan definiera här. Till exempel, " "HTTPS på andra portar än 443 är kända för att orsaka problem." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Webb server (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" "Webbplatsen kommer att finnas tillgänglig på http://" "{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Webb server (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" "Webbplatsen kommer att finnas tillgänglig på https://" "{0} " -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Secure Shell (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5293,8 +5237,8 @@ msgstr "" "För närvarande körs en installation eller uppgradering. Överväg att vänta " "tills den är klar innan du stänger av eller startar om." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Starta om" @@ -5344,6 +5288,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Stäng av nu" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5383,7 +5360,7 @@ msgstr "Webbproxy" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Anslut till {url} med proxy {proxy} på TCP {kind}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5400,7 +5377,7 @@ msgstr "" "quassel-klienter från ett skrivbord eller en mobil kan användas för att " "ansluta och koppla från den." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your Desktop och mobila-enheter är tillgängliga." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC-klient" @@ -5424,7 +5401,7 @@ msgstr "IRC-klient" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5439,7 +5416,7 @@ msgstr "" "clients\">stöds klientprogram. Radicale kan nås av alla användare med en " "{box_name} inloggning." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5449,12 +5426,12 @@ msgstr "" "skapandet av nya kalendrar och adressböcker. Det stöder inte att lägga till " "händelser eller kontakter, som måste göras med hjälp av en separat klient." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Kalender och adressbok" @@ -5527,7 +5504,7 @@ msgstr "" "address>) och ditt användarnamn. Om du klickar på sökknappen visas en lista " "över befintliga kalendrar och adressböcker." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Konfiguration av åtkomsträttigheter uppdaterat" @@ -5619,7 +5596,7 @@ msgstr "" "att följa olika webbplatser. När du lägger till ett feed aktiverar du " "autentisering och använder dina {box_name}-autentiseringsuppgifter." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Läsa och prenumerera på nyhetsflöden" @@ -5632,7 +5609,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "RSS Feed Generator" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5640,7 +5617,7 @@ msgstr "" "Samba gör det möjligt att dela filer och mappar mellan FreedomBox och andra " "datorer i ditt lokala nätverk." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5653,11 +5630,11 @@ msgstr "" "\\{hostname} (på Windows) eller SMB://{hostname}. local (på Linux och Mac). " "Det finns tre typer av shares som du kan välja mellan: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Öppen delning - tillgänglig för alla i ditt lokala nätverk." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5665,7 +5642,7 @@ msgstr "" "Gruppdelning - endast tillgänglig för FreedomBox-användare som ingår i " "freedombox-delningsgruppen." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5673,15 +5650,15 @@ msgstr "" "Hemdelning - varje användare i gruppen freedombox-share kan ha sitt eget " "privata utrymme." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Tillgång till privata delningar" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Nätverk För Fillagring" @@ -5767,15 +5744,15 @@ msgstr "Resursnamn" msgid "Action" msgstr "Åtgärd" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS-disk" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Öppna Share" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Grupp Share" @@ -5801,7 +5778,7 @@ msgstr "Share resurs inaktiverat." msgid "Error disabling share: {error_message}" msgstr "Fel vid inaktivering av resurs: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5809,7 +5786,7 @@ msgstr "" "Searx är en sekretess-respektera Internet metasökning motor. Det aggregrates " "och visar resultat från flera sökmotorer." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5817,39 +5794,39 @@ msgstr "" "Searx kan användas för att undvika spårning och profilering av sökmotorer. " "Den lagrar inga cookies som standard." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Sök på webben" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Webbsökning" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Säker sökning" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "Välj det standard familjefilter som ska användas för sökresultaten." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Måttlig" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Strikt" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Tillåt offentlig åtkomst" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "Tillåt att det här programmet används av alla som kan nå det." @@ -6029,7 +6006,7 @@ msgstr "Bokmärken" msgid "Shaarlier" msgstr "Shaarli" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6039,7 +6016,7 @@ msgstr "" "Internet-trafik. Det kan användas för att kringgå Internetfiltrering och " "censur." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6052,7 +6029,7 @@ msgstr "" "enheter kan ansluta till denna proxy och deras data kommer att krypteras och " "proxied via Shadowsocks-servern." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6060,41 +6037,41 @@ msgstr "" "Till använda Shadowsocks efter setup, sätta den SOCKS5 genom fullmakt URL i " "din anordning, beter eller applicering till http://freedombox_address: 1080/" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Socks5 proxy" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Rekommenderas" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Server" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Serverns värdnamn eller IP-adress" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Server portnummer" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Lösenord som används för att kryptera data. Måste matcha serverns lösenord." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Krypteringsmetod. Måste matcha inställningen på servern." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6103,15 +6080,15 @@ msgstr "" "Med Sharing kan du dela filer och mappar på din {box_name} över webben med " "utvalda grupper av användare." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Sharing" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Namn på Share-mappen" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6119,27 +6096,27 @@ msgstr "" "En liten alfanumerisk sträng som unikt identifierar en resurs. Exempel: " "Media ." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Sökväg för Share" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Disk Sök väg till en mapp på den här servern som du tänker dela." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Offentlig Share" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Gör filer i den här mappen tillgängliga för alla med länken." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Användargrupper som kan läsa filerna i Share:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6147,11 +6124,11 @@ msgstr "" "Användare av de valda användargrupperna kommer att kunna läsa filerna i " "Share." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Det finns redan en share med det här namnet." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "Shares ska antingen vara offentliga eller delas med minst en grupp" @@ -6188,19 +6165,19 @@ msgstr "Share tillagd." msgid "Add Share" msgstr "Lägg till share" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Share redigerad." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Redigera share" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Share borttagen." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6210,7 +6187,7 @@ msgstr "" "Dessa kan användas för att återställa systemet till ett tidigare känt skick " "i händelse av oönskade ändringar i systemet." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6221,7 +6198,7 @@ msgstr "" "även före och efter en programvaruinstallation. Äldre ögonblicksbilder " "kommer att rensas automatiskt enligt inställningarna nedan." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for säkerhetskopior eftersom de bara kan lagras på " "samma partition. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Ögonblicksbilder av lagring" @@ -6335,7 +6312,7 @@ msgstr "Datum" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Ta bort ögonblicksbilder" @@ -6389,57 +6366,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "Återställning till ögonblicksbild #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "manuellt skapad" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "Tidslinjen" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Hantera ögonblicksbilder" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Skapade ögonblicksbild." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Lagring ögonblicksbildkonfiguration uppdaterad" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Åtgärdsfel: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Borttagna markerade ögonblicksbilder" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Ögonblicksbild används för närvarande. Vänligen försök igen senare." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Återställs till Snapshot #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Systemet måste startas om för att slutföra återställningen." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Återställning till ögonblicksbild" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6451,7 +6428,7 @@ msgstr "" "administrativa uppgifter, kopiera filer eller köra andra tjänster med sådana " "anslutningar." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Secure Shell-Server (SSH)" @@ -6489,14 +6466,6 @@ msgstr "Algoritm" msgid "Fingerprint" msgstr "Fingeravtryck" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "SSH-autentisering med lösenord inaktiverat." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "SSH-autentisering med lösenord aktiverat." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Enkel inloggning på" @@ -6509,7 +6478,7 @@ msgstr "Logga in" msgid "Logged out successfully." msgstr "Du har loggat ut framgångsrikt." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6520,106 +6489,106 @@ msgstr "" "{box_name}. Du kan visa lagringsmedia som för närvarande används, montera " "och demontera flyttbara media, expandera rotpartitionen etc." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Lagring" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} byte" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} Kib" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} Mib" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} Gib" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} Tib" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Åtgärden misslyckades." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Operationen avbröts." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Enheten lossnar redan." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "Åtgärden stöds inte på grund av saknade drivrutiner/verktygsstöd." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Åtgärden orsakade timeout." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "Åtgärden skulle väcka en disk som är i ett djupviloläge." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Försöker avmontera en enhet som är upptagen." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Operationen har redan avbrutits." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "Inte behörig att utföra den begärda åtgärden." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Enheten är redan monterad." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Enheten är inte monterad." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "Inte tillåtet att använda det begärda alternativet." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Enheten monteras av en annan användare." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Lågt utrymme på systempartitionen: {percent_used}% används, {free_space} " "fritt." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Lågt diskutrymme" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Diskfel förestående" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6628,39 +6597,39 @@ msgstr "" "Disk {id} rapporterar att den sannolikt kommer att misslyckas inom en snar " "framtid. Kopiera all data medan du fortfarande kan och byt ut enheten." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Ogiltigt katalognamn." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Katalogen finns inte." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Sökvägen är inte en katalog." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Katalogen är inte läsbar av användaren." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Katalogen är inte skrivbar av användaren." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Katalog" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Underkatalog (valfritt)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Share" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Annan katalog (specificera nedan)" @@ -6697,7 +6666,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Utöka root-partitionen" @@ -6720,30 +6689,30 @@ msgstr "" "åtgärden kommer %(expandable_root_size)s av ytterligare ledigt utrymme att " "vara tillgängligt i rotpartitionen." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Fel vid utökning av partitionen: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Partitionsutökning genomförd." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} kan kopplas ur på ett säkert sätt." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Enheten kan kopplas ur på ett säkert sätt." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Fel mata ut enhet: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6755,7 +6724,7 @@ msgstr "" "filer på en enhet kommer att replikeras automatiskt på alla andra enheter " "som också kör Syncthing." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6774,20 +6743,20 @@ msgstr "" "{box_name} är endast tillgängligt för användare som tillhör gruppen \"admin" "\" eller \"syncthing-access\"." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Administrera Syncthing-program" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Filsynkronisering" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6801,7 +6770,7 @@ msgstr "" "använder TOR Browser." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6810,40 +6779,40 @@ msgstr "" "En Tor SOCKS-port finns tillgängligt på din {box_name} för interna nätverk " "på TCP-port 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor Onion service" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor SOCKS-proxy" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor Bridge Relay" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor relä port tillgänglig" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 transport registrerad" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 transport registrerad" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Tillgång URL {url} på TCP {kind} via Tor" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bekräfta Tor-användning vid {url} på TCP {kind}" @@ -6963,11 +6932,11 @@ msgstr "Onion tjänst" msgid "Ports" msgstr "Portar" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Uppdatera konfigurationen" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Fel vid konfigurering av appen: {error}" @@ -7031,7 +7000,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7041,7 +7010,7 @@ msgstr "" "utformats för att läsa nyheter från vilken plats som helst, samtidigt som du " "känner dig så nära en riktig stationär applikation som möjligt." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7050,7 +7019,7 @@ msgstr "" "När aktiverat kan Tiny Tiny RSS nås av alla " "användare som tillhör gruppen feed-reader." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7058,11 +7027,11 @@ msgstr "" "När du använder en mobil eller stationär applikation för Tiny Tiny RSS, " "Använd URL/tt-rss-app/\" för att ansluta." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Läsare för nyhetsflödet" @@ -7070,13 +7039,13 @@ msgstr "Läsare för nyhetsflödet" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" "Sök efter och installera de senaste program-och säkerhetsuppdateringarna." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7089,22 +7058,22 @@ msgstr "" "systemet bedöms vara nödvändigt, det sker automatiskt vid 02:00 orsakar alla " "apps för att vara tillgängligt en kort stund." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Mjukvaruuppdatering" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox uppdaterad" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Det gick inte att starta distributionsuppdatering" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7115,11 +7084,11 @@ msgstr "" "Distributionsuppdateringen kommer att göras ett nytt behov efter 24 timmar, " "om det är aktiverat." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Distributionsuppdateringen har startats" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7295,44 +7264,44 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Uppgradera testdistributionen nu" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "Fel vid konfigurering av obevakad uppgraderingar: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Automatiska uppgraderingar aktiverade" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Automatiska uppgraderingar inaktiverade" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Distributionsuppgradering aktiverad" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Distributionsuppgradering inaktiverad" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Uppgraderingsprocessen påbörjades." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Det gick inte att starta uppgraderingen." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Frekventa funktionsuppdateringar aktiverade." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Startar distributionsuppgraderingstest." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7343,7 +7312,7 @@ msgstr "" "ett användarkonto för att vara en del av en grupp för att auktorisera " "användaren att komma åt appen." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7354,15 +7323,15 @@ msgstr "" "över appar som är relevanta för dem på startsidan. Endast användare av " "gruppen admin kan dock ändra appar eller Systeminställningar." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Användare och grupper" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Tillgång till alla tjänster och systeminställningar" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Kontrollera LDAP-posten \"{search_item}\"" @@ -7382,11 +7351,11 @@ msgstr "" "Krävs. 150 tecken eller färre. Engelska bokstäver, siffror och endast @/./-/" "_ ." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Auktoriseringslösenord" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7394,11 +7363,11 @@ msgstr "" "Ange lösenordet för användaren \"{user}\" för att godkänna " "kontomodifieringar." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Ogiltigt lösenord." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7412,12 +7381,12 @@ msgstr "" "administratörsgruppen kommer att kunna logga in på alla tjänster. De kan " "också logga in på systemet via SSH och har administratörsprivilegier (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Det gick inte att skapa LDAP-användare: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Det gick inte att lägga till ny användare i gruppen {group} : {error}" @@ -7436,42 +7405,42 @@ msgstr "" "systemet utan att använda ett lösenord. Du kan ange flera nycklar, en på " "varje rad. Tomma rader och rader som börjar med # kommer att ignoreras." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Det gick inte att byta namn på LDAP-användare." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Det gick inte att ta bort användare från gruppen." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Det gick inte att lägga till användare i gruppen." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Det går inte att ange SSH-nycklar." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Det gick inte att ändra användarstatus." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Det gick inte att ändra användarlösenordet för LDAP." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Det gick inte att lägga till ny användare i administratörsgruppen: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Det gick inte att begränsa konsolåtkomst: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Användarkonto skapat, du är nu inloggad" @@ -7488,12 +7457,12 @@ msgstr "Spara lösenord" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Skapa användare" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Ta bort användare" @@ -7534,13 +7503,19 @@ msgid "The following administrator accounts exist in the system." msgstr "Följande administratörskonton finns i systemet." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Ta bort dessa konton från kommandoraden och uppdatera sidan för att skapa " "ett konto som är användbart med %(box_name)s. På kommandoraden kör kommandot " @@ -7549,7 +7524,7 @@ msgstr "" "detta steg." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Användare" @@ -7582,34 +7557,34 @@ msgstr "" msgid "Save Changes" msgstr "Spara ändringar" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Användaren %(username)s skapades." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Användaren %(username)s har uppdaterats." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Redigera användar" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Användare {user} borttagen." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Det gick inte att ta bort LDAP-användare." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Ändra lösenord" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Lösenordet har ändrats." @@ -7947,7 +7922,7 @@ msgstr "Ta bort anslutning till server" msgid "Server deleted." msgstr "Servern har tagits bort." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7961,7 +7936,7 @@ msgstr "" "med hjälp av teman. Administrationsgränssnittet och producerade webbsidor är " "lämpliga för mobila enheter." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7975,7 +7950,7 @@ msgstr "" "administratörsgränssnittet för bättre webbadresser till dina sidor och " "inlägg." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -7986,7 +7961,7 @@ msgstr "" "sidan som ett bokmärke för att nå administrationsgränssnittet i " "framtiden." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -7996,12 +7971,12 @@ msgstr "" "databasuppgradering från administratörsgränssnittet. Ytterligare plugins " "eller teman kan installeras och uppgraderas på egen risk." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Webbplats och blogg" @@ -8018,7 +7993,7 @@ msgstr "" "WordPress-webbplatsen eller bloggen. Aktivera endast efter den första " "installationen av WordPress." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8039,7 +8014,7 @@ msgstr "" "på en plats med hjälp av sök-, kart- och kalendervyer. Enskilda foton kan " "delas med andra genom att skicka en direktlänk." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8050,11 +8025,11 @@ msgstr "" "i Zoph. För ytterligare användare måste konton skapas både i {box_name} och " "i Zoph med samma användarnamn." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Foto Organizer" @@ -8107,96 +8082,92 @@ msgstr "Väntar på att starta: {name}" msgid "Finished: {name}" msgstr "Avslutad: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "Paket {expression} är inte tillgänglig för installation" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Paketet {package_name} är den senaste versionen ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Fel vid körning av apt-get" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "Installera" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "ladda ner" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "Mediabyte" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "konfigurationsfil: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Timeout väntar på pakethanteraren" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Installera app" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Uppdatera app" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Fel vid installation av app: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Fel vid uppdatering av app: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Fel vid installation av app: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Fel vid uppdatering av app: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "App installerad." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "App uppdaterad" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Avinstallera app" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Fel vid avinstallation av app: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Fel vid avinstallation av appen: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "Appen avinstallerad." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Uppdatera appaket" @@ -8255,53 +8226,54 @@ msgstr "Installation" msgid "Service %(service_name)s is not running." msgstr "Tjänsten %(service_name)s körs inte." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Kärnfunktioner och webbgränssnitt för %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Hem" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Hem" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Appar" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Appar" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " System" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "System" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Ändra lösenord" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Stänga ner" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Logga ut" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Välj språk" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Logga in" @@ -8592,6 +8564,75 @@ msgstr "innan du avinstallerar {app_id}" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Aktivera DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Aktivera Domain Name System Security Extensions" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Brandväggsdemonen körs inte. Vänligen starta den. Brandväggen är " +#~ "aktiverad som standard på %(box_name)s. På ett Debian-baserade system " +#~ "(till exempel %(box_name)s) Du kan starta den med kommandot \"service " +#~ "firewalld start\", alternativt, vid ett system med systemd \"systemctl " +#~ "start firewalld\"." + +#~ msgid "Migrate to ECC" +#~ msgstr "Migrera till ECC" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "Din OpenVPN-installation använder för närvarande RSA. Om du byter till " +#~ "den moderna Elliptic Curve Cryptography förbättrar hastigheten för att " +#~ "upprätta en anslutning och säkerhet. Den här åtgärden är oåterkallelig. " +#~ "Det bör bara ta några minuter på de flesta enda ombord datorer." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "Alla nya installationer av OpenVPN på %(box_name)s kommer att använda ECC " +#~ "som standard. Vi rekommenderar migrering så snart som möjligt." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ " Varning: Befintliga klientprofiler kommer att ogiltigförklaras av " +#~ "den här åtgärden. Alla OpenVPN-användare på %(box_name)s måste hämta sina " +#~ "nya profiler. OpenVPN-klienter som är kompatibla med ECC bör användas för " +#~ "att ansluta till den här servern." + +#~ msgid "Migrate" +#~ msgstr "Flytta" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "SSH-autentisering med lösenord inaktiverat." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "SSH-autentisering med lösenord aktiverat." + +#~ msgid "Error running apt-get" +#~ msgstr "Fel vid körning av apt-get" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Kärnfunktioner och webbgränssnitt för %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Nätverksanslutningar" diff --git a/plinth/locale/ta/LC_MESSAGES/django.po b/plinth/locale/ta/LC_MESSAGES/django.po index 580ba897d..e96490446 100644 --- a/plinth/locale/ta/LC_MESSAGES/django.po +++ b/plinth/locale/ta/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -110,17 +110,17 @@ msgstr "" msgid "{box_name} Web Interface (Plinth)" msgstr "" -#: plinth/modules/apache/components.py:126 +#: plinth/modules/apache/components.py:121 #, python-brace-format msgid "Access URL {url} on tcp{kind}" msgstr "" -#: plinth/modules/apache/components.py:129 +#: plinth/modules/apache/components.py:124 #, python-brace-format msgid "Access URL {url}" msgstr "" -#: plinth/modules/avahi/__init__.py:26 +#: plinth/modules/avahi/__init__.py:24 #, python-brace-format msgid "" "Service discovery allows other devices on the network to discover your " @@ -131,48 +131,48 @@ msgid "" "network." msgstr "" -#: plinth/modules/avahi/__init__.py:49 +#: plinth/modules/avahi/__init__.py:47 msgid "Service Discovery" msgstr "" -#: plinth/modules/avahi/__init__.py:62 +#: plinth/modules/avahi/__init__.py:60 msgid "Local Network Domain" msgstr "" -#: plinth/modules/backups/__init__.py:27 +#: plinth/modules/backups/__init__.py:24 msgid "Backups allows creating and managing backup archives." msgstr "" -#: plinth/modules/backups/__init__.py:48 plinth/modules/backups/__init__.py:199 -#: plinth/modules/backups/__init__.py:244 +#: plinth/modules/backups/__init__.py:44 plinth/modules/backups/__init__.py:169 +#: plinth/modules/backups/__init__.py:214 msgid "Backups" msgstr "" -#: plinth/modules/backups/__init__.py:196 +#: plinth/modules/backups/__init__.py:166 msgid "" "Enable an automatic backup schedule for data safety. Prefer an encrypted " "remote backup location or an extra attached disk." msgstr "" -#: plinth/modules/backups/__init__.py:202 +#: plinth/modules/backups/__init__.py:172 msgid "Enable a Backup Schedule" msgstr "" -#: plinth/modules/backups/__init__.py:206 -#: plinth/modules/backups/__init__.py:253 -#: plinth/modules/storage/__init__.py:326 +#: plinth/modules/backups/__init__.py:176 +#: plinth/modules/backups/__init__.py:223 plinth/modules/privacy/__init__.py:71 +#: plinth/modules/storage/__init__.py:313 #, python-brace-format msgid "Go to {app_name}" msgstr "" -#: plinth/modules/backups/__init__.py:241 +#: plinth/modules/backups/__init__.py:211 #, python-brace-format msgid "" "A scheduled backup failed. Past {error_count} attempts for backup did not " "succeed. The latest error is: {error_message}" msgstr "" -#: plinth/modules/backups/__init__.py:249 +#: plinth/modules/backups/__init__.py:219 msgid "Error During Backup" msgstr "" @@ -304,7 +304,7 @@ msgstr "" msgid "Key in Repository" msgstr "" -#: plinth/modules/backups/forms.py:176 plinth/modules/searx/forms.py:15 +#: plinth/modules/backups/forms.py:176 plinth/modules/searx/forms.py:14 msgid "None" msgstr "" @@ -368,37 +368,37 @@ msgstr "" msgid "Select verified SSH public key" msgstr "" -#: plinth/modules/backups/repository.py:34 +#: plinth/modules/backups/repository.py:30 msgid "" "Connection refused - make sure you provided correct credentials and the " "server is running." msgstr "" -#: plinth/modules/backups/repository.py:41 +#: plinth/modules/backups/repository.py:37 msgid "Connection refused" msgstr "" -#: plinth/modules/backups/repository.py:48 +#: plinth/modules/backups/repository.py:44 msgid "Repository not found" msgstr "" -#: plinth/modules/backups/repository.py:53 +#: plinth/modules/backups/repository.py:49 msgid "Incorrect encryption passphrase" msgstr "" -#: plinth/modules/backups/repository.py:58 +#: plinth/modules/backups/repository.py:54 msgid "SSH access denied" msgstr "" -#: plinth/modules/backups/repository.py:64 +#: plinth/modules/backups/repository.py:60 msgid "Repository path is neither empty nor is an existing backups repository." msgstr "" -#: plinth/modules/backups/repository.py:147 +#: plinth/modules/backups/repository.py:145 msgid "Existing repository is not encrypted." msgstr "" -#: plinth/modules/backups/repository.py:331 +#: plinth/modules/backups/repository.py:335 #, python-brace-format msgid "{box_name} storage" msgstr "" @@ -453,7 +453,7 @@ msgid "Create Location" msgstr "" #: plinth/modules/backups/templates/backups_add_repository.html:19 -#: plinth/modules/gitweb/views.py:54 +#: plinth/modules/gitweb/views.py:51 msgid "Create Repository" msgstr "" @@ -676,7 +676,7 @@ msgstr "" msgid "Mounting failed" msgstr "" -#: plinth/modules/bepasty/__init__.py:21 +#: plinth/modules/bepasty/__init__.py:16 msgid "" "bepasty is a web application that allows large files to be uploaded and " "shared. Text and code snippets can also be pasted and shared. Text, image, " @@ -684,7 +684,7 @@ msgid "" "can be set to expire after a time period." msgstr "" -#: plinth/modules/bepasty/__init__.py:25 +#: plinth/modules/bepasty/__init__.py:20 msgid "" "bepasty does not use usernames for login. It only uses passwords. For each " "password, a set of permissions can be selected. Once you have created a " @@ -692,7 +692,7 @@ msgid "" "permissions." msgstr "" -#: plinth/modules/bepasty/__init__.py:29 +#: plinth/modules/bepasty/__init__.py:24 msgid "" "You can also create multiple passwords with the same set of privileges, and " "distribute them to different people or groups. This will allow you to later " @@ -700,39 +700,39 @@ msgid "" "the list." msgstr "" -#: plinth/modules/bepasty/__init__.py:36 plinth/modules/bepasty/__init__.py:45 +#: plinth/modules/bepasty/__init__.py:31 plinth/modules/bepasty/__init__.py:40 msgid "Read a file, if a web link to the file is available" msgstr "" -#: plinth/modules/bepasty/__init__.py:37 +#: plinth/modules/bepasty/__init__.py:32 msgid "Create or upload files" msgstr "" -#: plinth/modules/bepasty/__init__.py:38 +#: plinth/modules/bepasty/__init__.py:33 msgid "List all files and their web links" msgstr "" -#: plinth/modules/bepasty/__init__.py:39 +#: plinth/modules/bepasty/__init__.py:34 msgid "Delete files" msgstr "" -#: plinth/modules/bepasty/__init__.py:40 +#: plinth/modules/bepasty/__init__.py:35 msgid "Administer files: lock/unlock files" msgstr "" -#: plinth/modules/bepasty/__init__.py:44 +#: plinth/modules/bepasty/__init__.py:39 msgid "None, password is always required" msgstr "" -#: plinth/modules/bepasty/__init__.py:46 +#: plinth/modules/bepasty/__init__.py:41 msgid "List and read all files" msgstr "" -#: plinth/modules/bepasty/__init__.py:61 plinth/modules/bepasty/manifest.py:6 +#: plinth/modules/bepasty/__init__.py:56 plinth/modules/bepasty/manifest.py:6 msgid "bepasty" msgstr "" -#: plinth/modules/bepasty/__init__.py:63 +#: plinth/modules/bepasty/__init__.py:58 msgid "File & Snippet Sharing" msgstr "" @@ -746,7 +746,7 @@ msgstr "" #: plinth/modules/bepasty/forms.py:27 #: plinth/modules/bepasty/templates/bepasty.html:30 -#: plinth/modules/users/forms.py:108 plinth/modules/users/forms.py:234 +#: plinth/modules/users/forms.py:111 plinth/modules/users/forms.py:235 msgid "Permissions" msgstr "" @@ -779,35 +779,35 @@ msgstr "" #: plinth/modules/bepasty/templates/bepasty.html:29 #: plinth/modules/dynamicdns/forms.py:91 plinth/modules/networks/forms.py:213 -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password" msgstr "" -#: plinth/modules/bepasty/views.py:22 +#: plinth/modules/bepasty/views.py:19 msgid "admin" msgstr "" -#: plinth/modules/bepasty/views.py:23 +#: plinth/modules/bepasty/views.py:20 msgid "editor" msgstr "" -#: plinth/modules/bepasty/views.py:24 +#: plinth/modules/bepasty/views.py:21 msgid "viewer" msgstr "" -#: plinth/modules/bepasty/views.py:49 +#: plinth/modules/bepasty/views.py:47 msgid "Read" msgstr "" -#: plinth/modules/bepasty/views.py:50 +#: plinth/modules/bepasty/views.py:48 msgid "Create" msgstr "" -#: plinth/modules/bepasty/views.py:51 +#: plinth/modules/bepasty/views.py:49 msgid "List" msgstr "" -#: plinth/modules/bepasty/views.py:52 +#: plinth/modules/bepasty/views.py:50 #: plinth/modules/email/templates/email-aliases.html:24 #: plinth/modules/letsencrypt/templates/letsencrypt.html:86 #: plinth/modules/networks/templates/connection_show.html:56 @@ -819,41 +819,41 @@ msgstr "" msgid "Delete" msgstr "" -#: plinth/modules/bepasty/views.py:53 +#: plinth/modules/bepasty/views.py:51 msgid "Admin" msgstr "" -#: plinth/modules/bepasty/views.py:90 plinth/modules/searx/views.py:40 -#: plinth/modules/searx/views.py:51 plinth/modules/tor/views.py:75 +#: plinth/modules/bepasty/views.py:88 plinth/modules/searx/views.py:35 +#: plinth/modules/searx/views.py:46 plinth/modules/tor/views.py:73 #: plinth/modules/zoph/views.py:71 msgid "Configuration updated." msgstr "" -#: plinth/modules/bepasty/views.py:93 plinth/modules/email/views.py:48 -#: plinth/modules/gitweb/views.py:121 plinth/modules/searx/views.py:43 -#: plinth/modules/searx/views.py:54 plinth/modules/zoph/views.py:74 +#: plinth/modules/bepasty/views.py:91 plinth/modules/email/views.py:48 +#: plinth/modules/gitweb/views.py:117 plinth/modules/searx/views.py:38 +#: plinth/modules/searx/views.py:49 plinth/modules/zoph/views.py:74 msgid "An error occurred during configuration." msgstr "" -#: plinth/modules/bepasty/views.py:105 +#: plinth/modules/bepasty/views.py:103 msgid "Password added." msgstr "" -#: plinth/modules/bepasty/views.py:110 +#: plinth/modules/bepasty/views.py:108 msgid "Add Password" msgstr "" -#: plinth/modules/bepasty/views.py:127 +#: plinth/modules/bepasty/views.py:122 msgid "Password deleted." msgstr "" -#: plinth/modules/bind/__init__.py:25 +#: plinth/modules/bind/__init__.py:17 msgid "" "BIND enables you to publish your Domain Name System (DNS) information on the " "Internet, and to resolve DNS queries for your user devices on your network." msgstr "" -#: plinth/modules/bind/__init__.py:29 +#: plinth/modules/bind/__init__.py:21 #, python-brace-format msgid "" "Currently, on {box_name}, BIND is only used to resolve DNS queries for other " @@ -861,31 +861,23 @@ msgid "" "connection from {box_name}." msgstr "" -#: plinth/modules/bind/__init__.py:74 +#: plinth/modules/bind/__init__.py:40 msgid "BIND" msgstr "" -#: plinth/modules/bind/__init__.py:75 +#: plinth/modules/bind/__init__.py:41 msgid "Domain Name Server" msgstr "" -#: plinth/modules/bind/forms.py:20 +#: plinth/modules/bind/forms.py:19 msgid "Forwarders" msgstr "" -#: plinth/modules/bind/forms.py:21 +#: plinth/modules/bind/forms.py:20 msgid "" "A list DNS servers, separated by space, to which requests will be forwarded" msgstr "" -#: plinth/modules/bind/forms.py:25 -msgid "Enable DNSSEC" -msgstr "" - -#: plinth/modules/bind/forms.py:26 -msgid "Enable Domain Name System Security Extensions" -msgstr "" - #: plinth/modules/bind/templates/bind.html:11 msgid "Serving Domains" msgstr "" @@ -917,19 +909,20 @@ msgstr "" msgid "Refresh IP address and domains" msgstr "" -#: plinth/modules/bind/views.py:71 plinth/modules/config/views.py:99 -#: plinth/modules/coturn/views.py:41 plinth/modules/deluge/views.py:42 -#: plinth/modules/dynamicdns/views.py:78 plinth/modules/ejabberd/views.py:96 -#: plinth/modules/email/views.py:45 plinth/modules/matrixsynapse/views.py:126 -#: plinth/modules/minetest/views.py:69 plinth/modules/mumble/views.py:37 -#: plinth/modules/pagekite/forms.py:78 plinth/modules/quassel/views.py:29 -#: plinth/modules/roundcube/views.py:32 plinth/modules/shadowsocks/views.py:59 -#: plinth/modules/transmission/views.py:43 plinth/modules/ttrss/views.py:26 -#: plinth/modules/wordpress/views.py:37 +#: plinth/modules/bind/views.py:61 plinth/modules/config/views.py:98 +#: plinth/modules/coturn/views.py:40 plinth/modules/deluge/views.py:35 +#: plinth/modules/dynamicdns/views.py:78 plinth/modules/ejabberd/views.py:95 +#: plinth/modules/email/views.py:45 plinth/modules/matrixsynapse/views.py:128 +#: plinth/modules/minetest/views.py:55 plinth/modules/mumble/views.py:37 +#: plinth/modules/pagekite/forms.py:74 plinth/modules/privacy/views.py:36 +#: plinth/modules/quassel/views.py:29 plinth/modules/roundcube/views.py:32 +#: plinth/modules/shadowsocks/views.py:53 plinth/modules/ssh/views.py:52 +#: plinth/modules/transmission/views.py:43 plinth/modules/ttrss/views.py:31 +#: plinth/modules/wordpress/views.py:31 msgid "Configuration updated" msgstr "" -#: plinth/modules/calibre/__init__.py:26 +#: plinth/modules/calibre/__init__.py:22 #, python-brace-format msgid "" "calibre server provides online access to your e-book collection. You can " @@ -937,7 +930,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/calibre/__init__.py:29 +#: plinth/modules/calibre/__init__.py:25 msgid "" "You can organize your e-books, extract and edit their metadata, and perform " "advanced search. calibre can import, export, or convert across a wide range " @@ -946,35 +939,35 @@ msgid "" "highlighted text. Content distribution using OPDS is currently not supported." msgstr "" -#: plinth/modules/calibre/__init__.py:35 +#: plinth/modules/calibre/__init__.py:31 msgid "" "Only users belonging to calibre group will be able to access the " "app. All users with access can use all the libraries." msgstr "" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "" @@ -1020,20 +1013,20 @@ msgstr "" msgid "Delete library %(library)s" msgstr "" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "" @@ -1071,24 +1064,24 @@ msgstr "" msgid "Server Administration" msgstr "" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1184,47 +1177,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1232,7 +1225,7 @@ msgid "" "who are otherwise unable connect to each other." msgstr "" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ddns." @@ -1462,11 +1455,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1578,7 +1571,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1633,13 +1626,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1761,14 +1754,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1776,7 +1769,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1786,13 +1779,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -1917,7 +1910,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -1925,7 +1918,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -1945,61 +1938,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2045,7 +2029,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2056,73 +2040,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2166,19 +2150,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2471,7 +2455,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2479,31 +2463,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2540,14 +2524,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2556,15 +2540,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2618,41 +2602,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2660,11 +2644,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2710,7 +2694,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2728,7 +2712,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2738,7 +2722,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2746,15 +2730,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2817,41 +2801,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2861,14 +2845,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -2949,7 +2933,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -2957,7 +2941,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -2966,18 +2950,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3046,35 +3030,35 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3083,11 +3067,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3132,7 +3116,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3291,19 +3275,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3649,7 +3633,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3754,7 +3738,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3770,7 +3754,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3783,7 +3767,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4319,7 +4303,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4330,20 +4314,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4353,61 +4337,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4416,33 +4368,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4451,87 +4403,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4565,29 +4517,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4629,8 +4581,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4672,6 +4624,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4703,7 +4686,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4714,7 +4697,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4734,7 +4717,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4744,19 +4727,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4815,7 +4798,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4882,7 +4865,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -4895,13 +4878,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -4910,31 +4893,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5012,15 +4995,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5046,51 +5029,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5243,14 +5226,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5259,97 +5242,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5386,26 +5369,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5413,14 +5396,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5514,7 +5497,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5562,57 +5545,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5620,7 +5603,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5653,14 +5636,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5673,7 +5648,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5681,143 +5656,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5851,7 +5826,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5869,30 +5844,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -5900,7 +5875,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -5912,20 +5887,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -5934,47 +5909,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6072,11 +6047,11 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "" @@ -6128,31 +6103,31 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " "user belonging to the feed-reader group." msgstr "" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6160,12 +6135,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6173,33 +6148,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6347,51 +6322,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6399,15 +6374,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6425,21 +6400,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6448,12 +6423,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6469,41 +6444,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6520,12 +6495,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6563,17 +6538,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6604,34 +6579,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -6940,7 +6915,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -6949,7 +6924,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -6958,26 +6933,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -6991,7 +6966,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7004,7 +6979,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7012,11 +6987,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7065,96 +7040,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7205,53 +7176,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" diff --git a/plinth/locale/te/LC_MESSAGES/django.po b/plinth/locale/te/LC_MESSAGES/django.po index 7f50f1f9e..0a29552be 100644 --- a/plinth/locale/te/LC_MESSAGES/django.po +++ b/plinth/locale/te/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-03-02 12:27+0000\n" "Last-Translator: James Valleroy \n" "Language-Team: Telugu calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1019,29 +1012,29 @@ msgstr "" "calibre సమూహానికి చెందిన వినియోగదారులు మాత్రమే యాప్‌ని యాక్సెస్ చేయగలరు. యాక్సెస్ ఉన్న " "వినియోగదారులందరూ అన్ని గ్రంధాలయంను ఉపయోగించవచ్చు" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "క్యాలిబర్ ఇ-బుక్ లైబ్రరీ ఉపయోగించండి" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "క్యాలిబర్" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "ఇ-బుక్ లైబ్రరీ" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "కొత్త గ్రంధాలయం పేరు" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "ఈ పేరుతో గ్రంధాలయం ఇప్పటికే ఉంది." @@ -1087,20 +1080,20 @@ msgstr "%(library)s లైబ్రరీకి వెళ్లుము" msgid "Delete library %(library)s" msgstr "గ్రంధాలయంను తొలగించు %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "గ్రంధాలయంను సృష్టించారు." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "గ్రంధాలయంని సృష్టిస్తున్నప్పుడు లోపం సంభవించింది." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} తొలగించబడింది." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "{name} ను తొలగించలేము: {error}" @@ -1146,7 +1139,7 @@ msgstr "కాక్పిట్" msgid "Server Administration" msgstr "సేవిక పరిపాలన" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1154,18 +1147,18 @@ msgstr "" "ఇక్కడ మీరు ఆతిథ్య నామం అధికారక్షేత్రం మహాతలంసేవిక మొదలైన కొన్ని సాధారణ రూపకరణ ఎంపికలను అమరిక " "చేయవచ్చు." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "సాధారణ ఆకృతీకరణ" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "ఆకృతీకరణ" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1276,47 +1269,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "ఆతిథ్యనామం అమర్చుటలో లోపం: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "ఆతిథ్యనామం అమర్చు" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "అధికారక్షేత్రం పేరు అమర్పులోపం: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "అధికారక్షేత్రం పేరు అమర్పు" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "వెబ్‌సర్వర్ హోమ్ పేజీని సెట్ చేయడంలో లోపం: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "వెబ్ సర్వర్ హోమ్ పేజీ సెట్ చేయబడింది" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "అధికారక్షేత్రం పేరు అమర్పులోపం: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "అధునాతన అనువర్తనాలు మరియు విశేషాంశాలు చూపబడుతున్నాయి" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "అధునాతన అనువర్తనాలు మరియు విశేషాంశాలు దాచబడుతున్నాయి" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1327,7 +1320,7 @@ msgstr "" "సమావేశాలను సులభతరం చేయడానికి ఒక సర్వర్. WebRTC, SIP మరియు ఇతర కమ్యూనికేషన్ సర్వర్‌లు ఒకదానికొకటి " "కనెక్ట్ చేయలేని పార్టీల మధ్య కాల్‌ని ఏర్పాటు చేయడానికి దీన్ని ఉపయోగించవచ్చు." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse or ejabberd ఇక్కడ అందించిన వివరాలతో రూపకరణచేయాలి." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "కోటుర్న్" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "విఓఐపీ సహాయకుడు" @@ -1397,11 +1390,11 @@ msgstr "సమయమండలం అమర్పులోపం: {exception}" msgid "Time zone set" msgstr "సమయమండలం ఏర్పాటు చేయబడినది" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "డీలడ్జ్ అనేది జాల UI కలిగివున్న ఒక బిట్ టోరెంట్ కక్షిదారు." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1410,16 +1403,16 @@ msgstr "" "a> అనే మార్గంలో అందుబాటులోనుంటుంది. ప్రధమ పాస్‌వర్డ్ గా 'డెల్యూజ్' ఉంటుంది, కానీ మీరు లాగ్ ఇన్ " "అయినవెంటనే మీ పాస్‌వర్డ్ ను మార్చుకోవాలి." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "బిట్ టోరెంట్ అనువర్తనాలను ఉపయోగించి ఫైళ్లను డౌన్లోడ్ చేయండి" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "డెలూజ్" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "బిట్ టొరెంట్ వెబ్ క్లయింట్" @@ -1545,7 +1538,7 @@ msgstr "ఫలితం" msgid "Diagnostic Test" msgstr "లక్షణాల పరీక్ష" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1556,7 +1549,7 @@ msgstr "" "అప్పుడు ఇతరులు అంతర్జాలంలో మిమల్ని కనుగొనడానికి కష్టం ఆవతుంది. అప్పుడు వారు ఈ {box_name} " "అందించే సేవలను కనుగోనలేరు." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1572,7 +1565,7 @@ msgstr "" "అనుమతిస్తుంది. తరువాత, సర్వర్ కొత్త IP మీ DNS పేరు కేటాయిస్తుంది, మరియు ఇంటర్నెట్ నుండి ఎవరైనా మీ " "DNS పేరు అడుగుతాడు ఉంటే, వారు మీ ప్రస్తుత ఐ.పీ. చిరునామాతో సమాధానం పొందుతారు." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1585,11 +1578,11 @@ msgstr "" "\" target=\"_blank\"> 3 freedns.afraid.org 4 ఉచిత నవీకరణ URL ఆధారిత సేవలు " "కనుగొనవచ్చు." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "గతిక DNS కక్షిదారు" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "డైనమిక్ డొమైన్ పేరు" @@ -1713,7 +1706,7 @@ msgstr "ఇది అవసరమేయిన్న క్షేత్రం." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1768,7 +1761,7 @@ msgstr "సర్వర్ కనెక్షన్ నిరాకరించ msgid "Already up-to-date" msgstr "ఇప్పటికే తాజాగా ఉంది" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1776,7 +1769,7 @@ msgstr "" "XMPP ఓపెన్ మరియు ప్రామాణికమైన కమ్యూనికేషన్ ప్రోటోకాల్. ఇక్కడ మీరు మీ XMPP సర్వర్ ని రూపకరణ మరియు " "అమలు చేయగలరు ejabberd అని ఆకృతీకరించవచ్చు." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client. ప్రారంభించబడినప్పుడు, ejabberdని ఏ " "వినియోగదారు అయినా {box_name} లాగిన్‌తో యాక్సెస్ చేయవచ్చు." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, fuzzy, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the kaanfigar పేజీలో సెటప్ చేయవచ్చు." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1935,7 +1928,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1945,7 +1938,7 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -1953,7 +1946,7 @@ msgstr "" "Roundcube యాప్ వినియోగదారులు ఇమెయిల్‌ను యాక్సెస్ " "చేయడానికి వెబ్ ఇంటర్‌ఫేస్‌ను అందిస్తుంది." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2082,7 +2075,7 @@ msgstr "పోర్టు" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2092,7 +2085,7 @@ msgstr "" "ఫైర్వాల్ అనేది మీ {box_name}కు జరిగే రవాణా రాకపోకలను నియంత్రించే ఒక భద్రతా వ్యవస్థ. దీనిని అనుమతించి " "సరిగా ఆకృతీకరిస్తే అంతర్జాలం నుంచి భద్రతా ముప్పు తగ్గుతుంది." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "ఫైర్వాల్" @@ -2112,52 +2105,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Port {name} ({details})బాహ్య నెట్‌వర్క్‌లకు అందుబాటులో లేదు" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"ఫైర్‌వాల్ డెమోన్ రన్ కావడం లేదు. దయచేసి దీన్ని అమలు చేయండి. %(box_name)sలో ఫైర్‌వాల్ డిఫాల్ట్‌గా " -"ప్రారంభించబడింది. ఏదైనా డెబియన్ ఆధారిత సిస్టమ్‌లో (%(box_name)s వంటివి) మీరు 'సర్వీస్ ఫైర్‌వాల్డ్ స్టార్ట్' " -"కమాండ్‌ని ఉపయోగించి లేదా systemd 'systemctl start firewalld' ఉన్న సిస్టమ్ విషయంలో దీన్ని అమలు " -"చేయవచ్చు." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "సేవ/పోర్ట్" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "క్రియాశీలం" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "నిలిపివేయబడింది" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "అనుమతించబడిన" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "అనుమతించబడిన (అంతర్గతంగా మాత్రమే)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "అనుమతించబడిన(బాహ్యం మాత్రమే)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "నిరోధించబడినవి" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2166,13 +2146,13 @@ msgstr "" "ఫైర్వాల్ పనితీరు స్వయాంచలికమైనది. మీరు ఒక సేవను అనుమతిస్తే అది ఫైర్వాల్లోకి కూడా అనుమతిచబడుతుంది. అలాగే " "మీరు ఒక సేవను ఆనుమతించకపోతే ఫైర్వాల్లో కూడా అది అనుమతింపబడదు." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "ఉన్నత స్థితి" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2224,7 +2204,7 @@ msgstr "అమరికను ప్రారంభించు" msgid "Setup Complete" msgstr "అమరక పూర్తయ్యింది" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2241,7 +2221,7 @@ msgstr "" "క్లయింట్‌లతో కోడ్ మార్పులను అప్‌లోడ్ చేయవచ్చు. మరియు మీరు మీ కోడ్‌ని ప్రపంచవ్యాప్తంగా ఉన్న వ్యక్తులతో " "పంచుకోవచ్చు." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2249,69 +2229,69 @@ msgstr "" "Gitని ఎలా ఉపయోగించాలో మరింత తెలుసుకోవడానికి Git ట్యుటోరియల్ని సందర్శించండి." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Git రిపోజిటరీలకు చదవడానికి-వ్రాయడానికి యాక్సెస్" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "గిట్వెబ్" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "సాధారణ Git హోస్టింగ్" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "చెల్లని రిపోజిటరీ URL." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "చెల్లని రిపోజిటరీ పేరు." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "ఇప్పటికే ఉన్న రిపోజిటరీని దిగుమతి చేయడానికి కొత్త రిపోజిటరీ పేరు లేదా URL." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "రిపోజిటరీ వివరణ" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "ఐచ్ఛికం, గిట్‌వెబ్‌లో ప్రదర్శించడానికి." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "రిపోజిటరీ యొక్క యజమాని పేరు" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "స్వంత రిపోజిటరీ" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "ఈ రిపోజిటరీని యాక్సెస్ చేయడానికి అధికారం ఉన్న వినియోగదారులను మాత్రమే అనుమతించండి." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "ఈ పేరుతో ఒక రిపోజిటరీ ఇప్పటికే ఉంది." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "రిపోజిటరీ పేరు" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" "భాగస్వామ్యాన్ని ప్రత్యేకంగా గుర్తించే లోయర్‌కేసన్ ఆల్ఫా-న్యూమరిక్ స్ట్రింగ్. ఉదాహరణ: <em>మీడియా</" "em>రిపోజిటరీ." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "డిఫాల్ట్ చర్మం" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb దీన్ని డిఫాల్ట్ బ్రాంచ్‌గా ప్రదర్శిస్తుంది." @@ -2355,19 +2335,19 @@ msgstr "Git రిపోజిటరీ %(name)sని తొలగి msgid "Delete this repository permanently?" msgstr "ఈ రిపోజిటరీని శాశ్వతంగా తొలగించాలా?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "రిపోజిటరీ సృష్టించబడింది." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "రిపోజిటరీని సృష్టిస్తున్నప్పుడు లోపం సంభవించింది." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "రిపోజిటరీ సవరించబడింది." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "రిపోజిటరీని సవరించండి" @@ -2716,7 +2696,7 @@ msgstr "{box_name} గురించి" msgid "{box_name} Manual" msgstr "{box_name} కరదీపిక" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2727,7 +2707,7 @@ msgstr "" "అనామక నెట్‌వర్క్ లేయర్. I2P ప్రపంచవ్యాప్తంగా పంపిణీ చేయబడిన వాలంటీర్-రన్ నెట్‌వర్క్ ద్వారా ఎన్‌క్రిప్టెడ్ ట్రాఫిక్‌ను " "పంపడం ద్వారా అనామకతను అందిస్తుంది." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2735,25 +2715,25 @@ msgstr "" "వారి పథకం హోమ్‌పేజీలో I2P గురించి " "మరింత సమాచారాన్ని కనుగొనండి." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "అందించిన వెబ్ ఇంటర్‌ఫేస్‌కు మొదటి సందర్శన కాన్ఫిగరేషన్ ప్రక్రియను ప్రారంభిస్తుంది." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "I2P కార్యక్షేతాన్ని నిర్వహించండి" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "ఇ౨ప్" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "అజ్ఞాత జాలిక" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P ప్రాతినిధ్య" @@ -2797,7 +2777,7 @@ msgstr "" "జోడించడం ద్వారా దస్త్రంలను సమాచార దిగుమతి చేయండి లేదా దస్త్రంలను భాగస్వామ్యం చేయడానికి కొత్త టొరెంట్‌ని " "సృష్టించండి." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2806,7 +2786,7 @@ msgstr "" "ikiwiki అనేది ఒక సాధారణ వికీ మరియు బ్లాగ్ అప్లికేషన్. ఇది మార్క్‌డౌన్‌తో సహా పలు తేలికపాటి మార్కప్ భాషలకు " "మరియు వ్యాఖ్యలు మరియు RSS ఫీడ్‌ల వంటి సాధారణ బ్లాగింగ్ కార్యాచరణకు మద్దతు ఇస్తుంది." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2819,15 +2799,15 @@ msgstr "" "సమూహం ఇప్పటికే ఉన్న వాటిని సవరించవచ్చు. వినియోగదారు " "కాన్ఫిగరేషన్లో మీరు ఈ అనుమతులను మార్చవచ్చు లేదా కొత్త వినియోగదారులను జోడించవచ్చు." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ఇకివికీ" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "వికీ మరియు బ్లాగ్" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "వికీ అనువర్తనాలను చూడండి మరియు మార్చండి" @@ -2883,41 +2863,41 @@ msgstr "" "ఈ చర్య పునర్విమర్శ చరిత్రతో సహా అన్ని పోస్ట్లు, పుటలు మరియు వ్యాఖ్యలు తొలగిస్తుంది. ఈ వికీ లేదా బ్లాగ్ " "శాశ్వతంగా తొలగించాలా?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "{name} వికీ సృష్టించబడింది." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "వికీని సృష్టించలేము: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "{name} బ్లాగు సృష్టించబడింది." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "బ్లాగు సృష్టించలేము: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} తొలగించబడింది." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "{title} ను తొలగించలేము: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "Gobby కోసం ఇన్ఫినోటెడ్ అనేది ఒక సర్వర్,ఒక సహకార టెక్స్ట్ ఎడిటర్." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2928,11 +2908,11 @@ msgstr "" "మరియు నిక్షిప్తం చెయుము. మొడటిగ గాబ్బి మరియు సెలెక్ట్ \"సర్వర్కు కనెక్ట్ చేయండి\" మరియు మీ ఎంటర్ చెయ్యండి " "{box_name}'s డొమైన్ పేరు." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "ఇన్ఫినోటెడ్" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "గాబ్బీ సేవకం" @@ -2980,7 +2960,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "జావాస్క్రిప్ట్ లైసెన్స్ సమాచరం" @@ -2999,7 +2979,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "చాట్ క్లయింట్" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3013,7 +2993,7 @@ msgstr "" "స్వయం చాలక డిజిటల్ సర్టిఫికెట్‌లను పొందవచ్చు మరియు అమర్చిపెట్టు చేయగలదు. ఇది సర్టిఫికేట్ అథారిటీ (CA) " "లెట్స్ ఎన్‌క్రిప్ట్‌కు అధికారక్షేత్రం యజమాని అని నిరూపించుకోవడం ద్వారా అలా చేస్తుంది." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3025,15 +3005,15 @@ msgstr "" "\"https://letsencrypt.org/repository/\">సభ్యుల ఒప్పందాన్ని ఎన్‌క్రిప్ట్ చేద్దాంని చదివి, " "అంగీకరించండి." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "లెట్స్ ఎన్క్రిప్ట్" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "యోగ్యతాపత్రాలు" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "పరీక్షించడం సాధ్యం కాదు: డొమైన్‌లు ఏవీ కాన్ఫిగర్ చేయబడలేదు." @@ -3098,7 +3078,7 @@ msgstr "" "తోబుట్టువుల అధికారక్షేత్రం కన్ఫిగర్ చేయబడ్డాయి. వారికి సర్టిఫికేట్లు పొందగలగటం అధికారక్షేత్రం " "ఆకృతీకరించుము. %(config_url)s" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3107,34 +3087,34 @@ msgstr "" "డొమైన్ {domain} కోసం సర్టిఫికేట్ విజయవంతంగా ఉపసంహరించబడింది. ఇది అమలులోకి రావడానికి కొన్ని క్షణాలు " "పట్టవచ్చు." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "{domain} డోమైన్ కొరకు సర్టిఫికేట్ ఉప్సంహరుంచుకొనడంలో విఫలం: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "{domain} డోమైన్ కొరకు సర్టిఫికేట్ సంపాదింపబడింది" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "{domain} డోమైన్ కొరకు సర్టిఫికేట్ సంపాదించుటలో విఫలం: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "{domain} డోమైన్ కొరకు సర్టిఫికేట్ తొలగించబడింది" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "{domain} డోమైన్ కొరకు ధృవీకరణపత్రం నిర్మూలించడంలో విఫలం: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3149,7 +3129,7 @@ msgstr "" "అందిస్తుంది మరియు పని చేయడానికి ఫోన్ నంబర్‌లు అవసరం లేదు. ఇచ్చిన మ్యాట్రిక్స్ సర్వర్‌లోని వినియోగదారులు " "ఫెడరేషన్ ద్వారా అన్ని ఇతర మ్యాట్రిక్స్ సర్వర్‌లలోని వినియోగదారులతో సంభాషించవచ్చు." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3158,7 +3138,7 @@ msgstr "" "Matrix Synapseకి ఆడియో/వీడియో కాల్‌ల కోసం STUN/TURN సర్వర్ అవసరం.Coturn యాప్‌ను ఇన్‌స్టాల్ చేయండి లేదా బాహ్య సర్వర్‌ను కాన్ఫిగర్ చేయండి." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "మ్యాట్రిక్స్ సినాప్స్" @@ -3258,7 +3238,7 @@ msgstr "" "కూడిన ఫెడరేషన్‌కు చెల్లుబాటు అయ్యే TLS ప్రమాణపత్రం అవసరం. దయచేసి ఒకదాన్ని పొందడానికి లెట్స్ ఎన్‌క్రిప్ట్కి వెళ్లండి." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3269,7 +3249,7 @@ msgstr "" "వెబ్సైటు నిర్మించే ఒక ఉపకరం. మీరు మీడియావికీని ఉపయోగించి ఒక వికీ లాంటి వెబ్సైటును ఏర్పాటు చేస్కుని మీ " "స్నేహితులతో సంయుక్తంగా నోట్స్ తీసుకొనవచ్చు." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3282,19 +3262,19 @@ msgstr "" "Special:" "CreateAccount పేజీకి వెళ్లడం ద్వారా MediaWiki నుండే మరిన్ని వినియోగదారు ఖాతాలను సృష్టించవచ్చు." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" "ఈ వికీకి లింక్తో ఎవరైనా దానిని చదవగలరు. లాగిన్ చేయబడిన వినియోగదారులు మాత్రమే కంటెంట్కు మార్పులు చేయవచ్చు." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "మీడియావికీ" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "వికీ" @@ -3383,39 +3363,39 @@ msgstr "అనుమతిపదం నవీకరించబడింది" msgid "Password update failed. Please choose a stronger password" msgstr "సమాచారాన్ని గుప్తీకరించాడానికి ఉపయోగించబడిన పాస్వర్డ్. తప్పకుండ సర్వర్ పాస్వర్డ్ తో సరిపోలాలి." -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "పబ్లిక్ రిజిస్ట్రేషన్లు ప్రారంభించబడ్డాయి" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "పబ్లిక్ రిజిస్ట్రేషన్లు నిలిపివేయబడ్డాయి" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "ప్రైవేట్ మోడ్ ప్రారంభించబడింది" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "ప్రైవేట్ మోడ్ నిలిపివేయబడింది" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "డిఫాల్ట్ చర్మం మార్చబడింది" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "అధికారక్షేత్రం పేరు అమర్పు" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "అధికారక్షేత్రం పేరు అమర్పు" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3427,11 +3407,11 @@ msgstr "" "{box_name}లో Minetest సర్వర్‌ని అమలు చేయడానికి అనుమతిస్తుంది. సర్వర్‌కి కనెక్ట్ చేయడానికి, Minetest క్లయింట్ అవసరం." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "మైన్ టెస్ట్" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "బ్లాక్ శాండ్‌బాక్స్‌" @@ -3479,7 +3459,7 @@ msgstr "నిరుపయోగం అయినప్పుడు, ఆటగా msgid "Address" msgstr "చిరునామా" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3665,7 +3645,7 @@ msgstr "సెక్యూర్ షెల్" msgid "Services" msgstr "సేవలు" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3673,13 +3653,13 @@ msgstr "" "కాన్ఫిగర్ చేయగల నెట్‌వర్క్ పరికరాలు. ఈథర్నెట్ మరియు Wi-Fi లేదా PPPoE ద్వారా ఇంటర్నెట్‌తో కనెక్ట్ అవ్వండి. " "నెట్‌వర్క్‌లోని ఇతర పరికరాలతో ఆ కనెక్షన్‌ని భాగస్వామ్యం చేయండి." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "ఇతర పద్ధతుల ద్వారా నిర్వహించబడే పరికరాలు ఇక్కడ ఆకృతీకరణకు అందుబాటులో ఉండకపోవచ్చు." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "అల్లికలు" @@ -4086,7 +4066,7 @@ msgstr "అనుసంధానాన్ని సవరించు" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "సవరించు" @@ -4191,7 +4171,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "పద్దతి" @@ -4207,7 +4187,7 @@ msgstr "సేవిక" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "అప్రమేయం" @@ -4220,7 +4200,7 @@ msgid "This connection is not active." msgstr "ఈ అనుసంధానం చురుకుగాలేదు." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "భద్రత" @@ -4792,7 +4772,7 @@ msgstr "{name} అనుసంధానం తొలగించబడింద msgid "Failed to delete connection: Connection not found." msgstr "అనుసంధానం తొలగించడం విఫలమైంది: అనుసంధానం దొరకలేదు." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4808,20 +4788,20 @@ msgstr "" "మిగిలిన ఇంటర్నెట్ను యాక్సెస్ చేయవచ్చు మీ {box_name} 1 అనుసంధానించవచ్చు అదనపు భద్రత మరియు " "అనామకత్వం కోసం." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "అనుసంధాన రకం విపిన్ సేవలకు" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "తెరచిన విపిన్" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "వర్చువల్ ప్రైవేట్ నెట్వర్క్" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4832,56 +4812,16 @@ msgstr "" msgid "Tunnelblick" msgstr "టన్నెల్‌బ్లిక్" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "ECCకి మైగ్రేట్ చేయండి" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"మీ OpenVPN ఇన్‌స్టాలేషన్ ప్రస్తుతం RSAని ఉపయోగిస్తోంది. ఆధునిక ఎలిప్టిక్ కర్వ్ క్రిప్టోగ్రఫీకి మారడం కనెక్షన్ " -"మరియు భద్రతను ఏర్పాటు చేసే వేగాన్ని మెరుగుపరుస్తుంది. ఈ ఆపరేషన్ కోలుకోలేనిది. చాలా సింగిల్ బోర్డ్ " -"కంప్యూటర్‌లలో దీనికి కొన్ని నిమిషాలు మాత్రమే పడుతుంది." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"%(box_name)sలో OpenVPN యొక్క అన్ని కొత్త ఇన్‌స్టాలేషన్‌లు డిఫాల్ట్‌గా ECCని ఉపయోగిస్తాయి. వీలైనంత త్వరగా " -"వలస వెళ్లాలని మేము సిఫార్సు చేస్తున్నాము." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"హెచ్చరిక: ఈ ఆపరేషన్ ద్వారా ఇప్పటికే ఉన్న క్లయింట్ ప్రొఫైల్‌లు చెల్లుబాటు కావు. %(box_name)sలోని " -"OpenVPN వినియోగదారులందరూ తప్పనిసరిగా వారి కొత్త ప్రొఫైల్‌లను డౌన్‌లోడ్ చేసుకోవాలి. ఈ సర్వర్‌కి కనెక్ట్ చేయడానికి " -"ECCకి అనుకూలమైన OpenVPN క్లయింట్‌లను ఉపయోగించాలి." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "మోడిగ్రేట్ చేయండి" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "స్థూల వివరం" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, fuzzy, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "బాక్స్_నామలు 1 యొక్క విపిన్ కనెక్ట్, మీరు ఒక ప్రొఫైల్ డౌన్లోడ్ మరియు మీ మొబైల్ లేదా డెస్క్టాప్ మిషన్పై ఓపెన్ప్ప్న్ " @@ -4890,16 +4830,17 @@ msgstr "" "2డాక్యుమెంటేషన్ &ల్టీ;/ఆ&జీత్; 3 టైటిల్=\"%బావీ క్స్_నామ ఆకృతీకరించుటకు ఎలా సిఫార్సు " "ఖాతాదారులకు మరియు సూచనలతో వాటిని. %(box_name)s" -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "ప్రొఫైల్ ప్రతి %(box_name)s వాడుకరికి నిర్ధిష్టమైనది. దాన్ని రహస్యంగా ఉంచండి." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "నా స్థూలవివరంల దిగుమతి" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4911,24 +4852,24 @@ msgstr "" "వ్యవస్థ. మీ {box_name} సేవలు మిగిలిన ఇంటర్నెట్‌లో అందుబాటులో లేనట్లయితే మాత్రమే మీకు ఇది అవసరం. ఇది " "క్రింది పరిస్థితులను కలిగి ఉంటుంది:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} పరిమితం చేయబడిన ఫైర్‌వాల్ వెనుక ఉంది." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "{box_name} మీరు నియంత్రించని (వైర్‌లెస్) రూటర్‌కి బందించబడింది ." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" "మీ ISP మీకు బాహ్య IP చిరునామాను అందించదు మరియు బదులుగా NAT ద్వారా ఇంటర్నెట్ కనెక్షన్‌ని అందిస్తుంది." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -4936,11 +4877,11 @@ msgstr "" "మీ ISP మీకు స్టాటిక్ IP చిరునామాను అందించదు మరియు మీరు ఇంటర్నెట్‌కి కనెక్ట్ అయిన ప్రతిసారీ మీ IP చిరునామా " "మారుతుంది." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "మీ ISP ఇన్‌కమింగ్ కనెక్షన్‌లను పరిమితం చేస్తుంది." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4953,23 +4894,23 @@ msgstr "" "\"https://pagekite.net\">pagekite.net. భవిష్యత్తులో దీని కోసం మీ స్నేహితుని " "{box_name}ని ఉపయోగించడం సాధ్యమవుతుంది." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "పేజ్‌కైట్" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "ప్రజా దృశ్యమానం" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "పేజ్‌కైట్ అధికారక్షేత్రం" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "సర్వర్ అధికారక్షేత్రం" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -4977,66 +4918,66 @@ msgstr "" "మీ పేజ్‌కైట్ సర్వర్‌ని ఎంచుకోండి. డిఫాల్ట్ pagekite.net సర్వర్‌ని ఉపయోగించడానికి \"pagekite.net\"ని సెట్ " "చేయండి." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "సర్వర్ పోర్ట్" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "మీ పేజ్‌కైట్ సర్వర్ యొక్క పోర్ట్ (డిఫాల్ట్: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "కైట్ పేరు" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "ఉదాహరణ: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "చెల్లని కైట్ పేరు" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "కైట్ రహస్యము" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" "గాలిపటంతో అనుబంధించబడిన రహస్యం లేదా గాలిపటంపై రహస్యం ఏదీ సెట్ చేయకుంటే మీ ఖాతా కోసం డిఫాల్ట్ రహస్యం." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "ప్రోటోకాల్" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "బాహ్య (ఫ్రంటెండ్) పోర్ట్" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "అంతర్గత (ఫ్రీడమ్బాక్స్) పోర్ట్" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "సబ్డొమైన్లు క్రియాశీలీకరించు" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "కస్టమ్ సర్వీస్ తొలగించబడింది" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "ఈ సేవ ఇప్పటికే ప్రామాణిక సేవగా అందుబాటులో ఉంది." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "అనుకూల సేవ జోడించబడింది" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "ఈ సేవ ఇప్పటికే ఉంది" @@ -5072,29 +5013,29 @@ msgstr "" "హెచ్చరిక:
మా PageKite ఫ్రంటెండ్ సర్వర్ మీరు ఇక్కడ నిర్వచించే చేయగల అన్ని ప్రోటోకాల్ / పోర్ట్ " "కాంబినేషన్ మద్దతు ఇవ్వకపోవచ్చు. ఉదాహరణకు, HTTPS 443 పోర్ట్లకు సమస్యలు కారణమవుతుంది." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "వెబ్ సేవిక (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "సైట్ http://{0} వద్ద అందుబాటులో ఉంటుంది" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "వెబ్ సేవిక (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "సైట్ https://{0} వద్ద అందుబాటులో ఉంటుంది" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "సెక్యూర్ షెల్ (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5143,8 +5084,8 @@ msgstr "" "ప్రస్తుతం సంస్థాపన లేదా నవీకరణ నడుస్తోంది. మూసివేయడానికి లేదా పునఃప్రారంభించడానికి ముందు ఇది పూర్తి " "అయ్యే వరకు వేచి ఉండండి." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "పునఃప్రారంభించండి" @@ -5193,6 +5134,39 @@ msgstr "" msgid "Shut Down Now" msgstr "ఇపుడు మూసివేయండి" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "ప్రివొక్సి" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5237,7 +5211,7 @@ msgstr "వెబ్ ప్రాక్సీ" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "టీసీపీ{kind} పై{proxy} తో యాక్సిస్ {url} చేయండి" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5253,7 +5227,7 @@ msgstr "" "అమలు చేయగలదు మరియు డెస్క్‌టాప్ లేదా మొబైల్ నుండి ఒకటి లేదా అంతకంటే ఎక్కువ క్వాసెల్ క్లయింట్‌లను కనెక్ట్ " "చేయడానికి మరియు డిస్‌కనెక్ట్ చేయడానికి ఉపయోగించవచ్చు." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your మొబైల్ పరికరాలు అందుబాటులో " "ఉన్నాయి." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "క్వాసెల్" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC క్లయింట్" @@ -5277,7 +5251,7 @@ msgstr "IRC క్లయింట్" msgid "Quasseldroid" msgstr "క్వాసెల్ డ్రొఇడ్" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, fuzzy, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5291,7 +5265,7 @@ msgstr "" "\"&జిత్ ;మద్దతు ఉన్న క్లయింట్ అప్లికేషన్&ల్టీ ;/ఆ &జిత్; అవసరం.\n" "రాడికల్ ఏ యూజర్ అయినా బాక్స్_నామలాగిన్ తో యాక్సెస్ చేయవచ్చు {box_name}" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5301,12 +5275,12 @@ msgstr "" "రూపొందించడానికి మాత్రమే మద్దతు ఇస్తుంది. ఈవెంట్‌లు లేదా పరిచయాలను జోడించడానికి ఇది మద్దతు ఇవ్వదు, ఇది " "ప్రత్యేక క్లయింట్‌ని ఉపయోగించి చేయాలి." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "రాడికేల్" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "క్యాలెండర్ మరియు అడ్రస్సు పుస్తకము" @@ -5378,7 +5352,7 @@ msgstr "" "శోధన బటన్‌పై క్లిక్ చేయడం ద్వారా ఇప్పటికే ఉన్న క్యాలెండర్‌లు మరియు చిరునామా పుస్తకాలు జాబితా చేయబడతాయి." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "సాంగత్యం హక్కుల కాన్ఫిగరేషన్ నవీకరించబడింది" @@ -5464,7 +5438,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "న్యూస్ ఫీడ్‌లను చదవడం మరియు చందాదారునిగా చేరు" @@ -5477,7 +5451,7 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5485,7 +5459,7 @@ msgstr "" "మీ స్థానిక నెట్‌వర్క్‌లోని ఫ్రీడమ్‌బాక్స్ మరియు ఇతర కంప్యూటర్ల మధ్య ఫైల్‌లు మరియు ఫోల్డర్‌లను పంచుకోవడానికి సాంబా " "అనుమతిస్తుంది." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5497,11 +5471,11 @@ msgstr "" "కంప్యూటర్‌లోని ఫైల్ మేనేజర్‌లో \\\\{hostname} (Windowsలో) లేదా smb://{hostname}.local " "(Linux మరియు Macలో) వద్ద యాక్సెస్ చేయవచ్చు. మీరు ఎంచుకోగల మూడు రకాల షేర్లు ఉన్నాయి: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "ఓపెన్ షేర్ - మీ స్థానిక నెట్‌వర్క్‌లోని ప్రతి ఒక్కరికీ అందుబాటులో ఉంటుంది." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5509,7 +5483,7 @@ msgstr "" "గ్రూప్ షేర్ - freedombox-share గ్రూపులో ఉన్న ఫ్రీడమ్‌బాక్స్ వినియోగదారులకు మాత్రమే అందుబాటులో " "ఉంటుంది." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5517,15 +5491,15 @@ msgstr "" "హోమ్ షేర్ - freedombox-share గ్రూపులో ఉన్న ప్రతి వినియోగదారుడు వారి స్వంత ప్రైవేట్ స్థలాన్ని కలిగి " "ఉంటారు." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "ప్రైవేటు షేర్లలో ప్రవేశం" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "సాంబా" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "నెట్‌వర్క్ దస్త్రంనిల్వ" @@ -5614,15 +5588,15 @@ msgstr "భాగస్వామ్యం పేరు" msgid "Action" msgstr "చర్య" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "ఫ్రీడమ్‌బాక్స్ OS డిస్క్" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "భాగస్వామ్యాన్ని తెరవండి" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "సమూహం భాగస్వామ్యం" @@ -5648,7 +5622,7 @@ msgstr "భాగస్వామ్యం నిలిపివేయబడి msgid "Error disabling share: {error_message}" msgstr "భాగస్వామ్యాన్ని నిలిపివేయడంలో లోపం: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5656,7 +5630,7 @@ msgstr "" "సెర్క్స్ అనేది గోప్యతను గౌరవించే ఒక మెటా-శోధన ఇంజిన్. ఇది బహుళ శోధన ఇంజిన్ల నుండి ఫలితాలను సమీకరించి, " "ప్రదర్శిస్తుంది." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5664,39 +5638,39 @@ msgstr "" "శోధన యంత్రాలు ద్వారా ట్రాకింగ్ మరియు ప్రొఫైలింగ్ను నివారించడానికి సెర్క్స్ ను ఉపయోగించవచ్చు. ఇది మాములుగా " "కుకీలను నిల్వ ఉంచుకోదు." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "అంతర్జాలమును శోధింపుము" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "సేర్క్స్" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "వెబ్ శోధన" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "సురక్షితశోధన" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "మీ శోధన ఫలితాలపైన అమలు చేయబడే కుటుంబ వడపోత విధానమును ఎంచుకొనండి." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "మితమైన" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "కఠినమైన" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "ప్రజా ప్రాప్తి అనుమతించు" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "ఈ అనువర్తనాన్ని చేరుకోగల ఎవరైనా ఉపయోగించడానికి అనుమతించండి." @@ -5870,7 +5844,7 @@ msgstr "బుక్‌మార్క్‌లు" msgid "Shaarlier" msgstr "షార్లియర్" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -5879,7 +5853,7 @@ msgstr "" "షాడోసాక్స్ మీ ఇంటర్నెట్ ట్రాఫిక్ను రక్షించేందుకు రూపొందించబడిన ఒక తేలికైన మరియు సురక్షిత సాక్స్5 ప్రాక్సీ. " "ఇది ఇంటర్నెట్ వడపోత మరియు సెన్సార్షిప్ను దాటడానికి ఉపయోగించవచ్చు." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5891,7 +5865,7 @@ msgstr "" "చేయగలదు. ఇది SOCKS5 ప్రాక్సీని కూడా అమలు చేస్తుంది. స్థానిక పరికరాలు ఈ ప్రాక్సీకి కనెక్ట్ చేయగలవు " "మరియు వాటి డేటా Shadowsocks సర్వర్ ద్వారా గుప్తీకరించబడుతుంది మరియు ప్రాక్సీ చేయబడుతుంది." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -5899,40 +5873,40 @@ msgstr "" "సెటప్ తర్వాత Shadowsocksని ఉపయోగించడానికి, మీ పరికరం, బ్రౌజర్ లేదా అప్లికేషన్‌లో SOCKS5 ప్రాక్సీ URLని " "http://freedombox_address:1080/కి సెట్ చేయండి" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "షాడోసాక్స్" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "సాక్స్5 ప్రాక్సీ" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "సిఫార్సు చేయబడింది" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "సర్వర్" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "సర్వర్ హోస్ట్ పేరు లేదా ఐపి చిరునామా" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "సర్వర్ పోర్ట్ సంఖ్య" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "సమాచారాన్ని గుప్తీకరించాడానికి ఉపయోగించబడిన పాస్వర్డ్. తప్పకుండ సర్వర్ పాస్వర్డ్ తో సరిపోలాలి." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "గుప్తీకరించు పద్దతి. సర్వర్ లోని సెట్టింగ్‌తో సరిపోలాలి." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -5941,51 +5915,51 @@ msgstr "" "వెబ్‌లో ఎంచుకున్న వినియోగదారుల సమూహాలతో మీ {box_name}లోని ఫైల్‌లు మరియు ఫోల్డర్‌లను భాగస్వామ్యం చేయడానికి " "భాగస్వామ్యం మిమ్మల్ని అనుమతిస్తుంది." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "భాగస్వామ్యం" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "షేర్ యొక్క పేరు" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "ప్రత్యేకంగా ఒక వాటాను గుర్తించే చిన్న అక్షర సంఖ్యా స్ట్రింగ్. ఉదాహరణ: media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "షేర్ యొక్క మార్గం" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "ఈ సర్వర్ పైన మీరు పంచుకోవాలి అనుకుంటున్న ఫోల్డర్ యొక్క డిస్క్ మార్గం." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "ప్రజా వాటా" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "ఈ ఫోల్డర్‌లోని ఫైల్‌లను లింక్ ఉన్న ఎవరికైనా అందుబాటులో ఉంచండి." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "భాగస్వామ్యంలోని ఫైళ్లను చదవగలిగే వినియోగదారుల సమూహాలు:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "ఎంచుకున్న వినియోగదారు సమూహాల వినియోగదారులు షేర్‌లోని ఫైల్‌లను చదవగలరు." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "ఈ పేరుతో ఒక వాటా ఇప్పటికే ఉంది." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "షేర్లు పబ్లిక్ గా ఉండాలి లేదా కనీసం ఒక గ్రూపుతో పంచుకోవాలి" @@ -6022,19 +5996,19 @@ msgstr "పంచుకోబడ్డ" msgid "Add Share" msgstr "వాటా జోడించండి" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "భాగస్వామ్యం సవరించబడింది." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "భాగస్వామ్యాన్ని సవరించండి" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "వాటా తొలగించబడింది." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6044,7 +6018,7 @@ msgstr "" "అవాంఛిత మార్పులు సంభవించినప్పుడు సిస్టమ్‌ను గతంలో తెలిసిన మంచి స్థితికి రోల్ బ్యాక్ చేయడానికి వీటిని " "ఉపయోగించవచ్చు." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6054,7 +6028,7 @@ msgstr "" "స్నాప్‌షాట్‌లు క్రమానుగతంగా తీసుకోబడతాయి (టైమ్‌లైన్ స్నాప్‌షాట్‌లు అని పిలుస్తారు) మరియు సాఫ్ట్‌వేర్ ఇన్‌స్టాలేషన్‌కు " "ముందు మరియు తర్వాత కూడా. దిగువ సెట్టింగ్‌ల ప్రకారం పాత స్నాప్‌షాట్‌లు స్వయంచాలకంగా శుభ్రం చేయబడతాయి." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for బ్యాకప్‌లకి ప్రత్యామ్నాయం కాదు, ఎందుకంటే అవి ఒకే విభజనలో " "మాత్రమే నిల్వ చేయబడతాయి. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "నిల్వ దృశ్యములు" @@ -6161,7 +6135,7 @@ msgstr "తేదీ" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "స్నాప్షాట్‌లను తొలగించు" @@ -6213,57 +6187,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "స్నాప్షాట్ #%(number)s కు రోల్‌బ్యాక్ చేయండి" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "మానవీయంగా సృష్టించబడింది" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "కాలక్రమం" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "సముచితమైనది" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "స్నాప్‌షాట్‌లను నిర్వహించండి" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "స్నాప్షాట్‌ సృష్టించబడినది." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "నిల్వ స్నాప్‌షాట్‌ల కాన్ఫిగరేషన్ నవీకరించబడింది" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "చర్య లోపం:{0}{1}{2}" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "ఎంచుకున్న స్నాప్‌షాట్‌లు తొలగించబడ్డాయి" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "స్నాప్‌షాట్ ప్రస్తుతం వాడుకలో ఉంది. దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "స్నాప్షాట్ #{number} కు తీస్కుని వెళ్ళబడింది." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "రొల్ల్బచ్క్ ని పూర్తి చేయడానికి వ్యవస్థను పునరుద్ధరించాలి." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "చాయాచిత్రం కు రొల్ల్బచ్క్ చేయండి" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6274,7 +6248,7 @@ msgstr "" "ఉపయోగిస్తుంది. అధీకృత రిమోట్ కంప్యూటర్ అటువంటి కనెక్షన్‌లను ఉపయోగించి అడ్మినిస్ట్రేషన్ పనులను చేయగలదు, " "ఫైల్‌లను కాపీ చేయగలదు లేదా ఇతర సేవలను అమలు చేయగలదు." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "సెక్యూర్ షెల్ (SSH) సర్వర్" @@ -6311,14 +6285,6 @@ msgstr "అల్గారిథం" msgid "Fingerprint" msgstr "వేలిముద్ర" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "SSH ప్రమాణీకరణ తో SSH ఆపివేయబడింది ." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "SSH ప్రమాణీకరణ తో SSH ఆపివేయబడింది ." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "సింగిల్ సైన్ ఆన్" @@ -6331,7 +6297,7 @@ msgstr "ప్రవేశించు" msgid "Logged out successfully." msgstr "విజయవంతంగా లాగ్ అవుట్ చేయబడింది." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6342,104 +6308,104 @@ msgstr "" "ప్రస్తుతం వాడుకలో ఉన్న స్టోరేజ్ మీడియాను వీక్షించవచ్చు, తొలగించగల మీడియాను మౌంట్ చేయవచ్చు మరియు అన్‌మౌంట్ " "చేయవచ్చు, రూట్ విభజనను విస్తరించవచ్చు మొదలైనవి." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "నిల్వ" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} బైట్లు" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} కిలోబైట్లు" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} మెగాబైట్లు" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} గిగాబైట్లు" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} టెరాబైట్లు" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "ఆపరేషన్ విఫలమైంది." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "ఆపరేషన్ రద్దు చేయబడింది." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "పరికరం ఇప్పటికే అన్‌మౌంట్ చేయబడుతోంది." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "డ్రైవర్/టూల్ సపోర్ట్ తప్పిపోయినందున ఆపరేషన్‌కు మద్దతు లేదు." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "ఆపరేషన్ టైమవుట్ అయింది." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "ఈ ఆపరేషన్ గాఢ నిద్రలో ఉన్న ఒక డిస్క్ ను మేల్కొలుపుతుంది." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "బిజీగా ఉన్న పరికరాన్ని అన్‌మౌంట్ చేయడానికి ప్రయత్నిస్తోంది." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "ఆపరేషన్ ఇప్పటికే రద్దు చేయబడింది." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "అభ్యర్థించిన ఆపరేషన్ చేయడానికి అధికారం లేదు." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "పరికరం ఇప్పటికే మౌంట్ చేయబడింది." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "పరికరం మౌంట్ చేయబడలేదు." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "అభ్యర్థించిన ఎంపికను ఉపయోగించడానికి అనుమతి లేదు." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "పరికరం మరొక వినియోగదారుచే మౌంట్ చేయబడింది." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "సిస్టమ్ విభజనలో తక్కువ స్థలం: {percent_used}% used, {free_space} ఉచితం." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "తక్కువ ఖని స్థలం" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "ఖని వైఫల్యం ఆసన్నమైంది" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6448,39 +6414,39 @@ msgstr "" "ఖని {id}సమీప భవిష్యత్తులో విఫలమయ్యే అవకాశం ఉందని నివేదిస్తోంది. మీరు చేయగలిగినప్పుడు ఏదైనా సమాచారంకాపీ " "చేసి, చోదకం భర్తీ చేయండి." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "డైరెక్టరీ పేరు చెల్లదు." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "డైరెక్టరీ ఉనికిలో లేదు." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "మార్గం అనేది డైరెక్టరీ కాదు." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "వినియోగదారు ద్వారా డైరెక్టరీ చదవబడలేదు." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "వినియోగదారు ద్వారా డైరెక్టరీ వ్రాయబడలేదు." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "డైరెక్టరీ" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "ఉప డైరెక్టరీ (ఐచ్ఛికం)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "పంచుకోబడ్డ" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "ఇతర డైరెక్టరీ (దిగువన పేర్కొనండి)" @@ -6517,7 +6483,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "రూట్ విభజనను విస్తరించు" @@ -6539,30 +6505,30 @@ msgstr "" "దయచేసి మీ సమాచారాన్ని బ్యాకప్ (భద్రపరచు కొనుట) చేస్కోండి. ఈ క్రియ తర్వాత %(expandable_root_size)s " "అధనపు సామర్ధ్యం మీ రూ విభజనలో అందుబాటులోకి వస్తుంది." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "విభజన విస్తరణలో దోషం: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "విభజనను విస్తరించడం విజయవంతమైనది." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} ని సురక్షితంగా తొలగించవచ్చు." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "పరికరాన్ని సురక్షితంగా తొలగించవచ్చు." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "పరికరాన్ని తొలగించడంలో లోపం: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6573,7 +6539,7 @@ msgstr "" "మరియు మొబైల్ ఫోన్. ఒక పరికరంలో ఫైల్‌లను సృష్టించడం, సవరించడం లేదా తొలగించడం అనేది సమకాలీకరణను అమలు " "చేసే అన్ని ఇతర పరికరాలలో స్వయంచాలకంగా పునరావృతమవుతుంది." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6590,20 +6556,20 @@ msgstr "" "సెట్ ప్రత్యేక ఫోల్డర్‌ల సెట్‌తో సమకాలీకరించబడవచ్చు.వెబ్ ఇంటర్‌ఫేస్ ఆన్ చేయబడింది{box_name} నిర్వాహకుడు \" " "లేదా \"సమకాలీకరణ-యాక్సెస్\" సమూహానికి చెందిన వినియోగదారులకు మాత్రమే అందుబాటులో ఉంటుంది." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "సమకాలీకరణ అప్లికేషన్‌ను నిర్వహించండి" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "సింక్ తింగ్" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "ఫైళ్ళ సమకాలీకరణ" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6616,7 +6582,7 @@ msgstr "" "టార్ ప్రాజెక్ట్ మీరు టార్ బ్రౌజర్ ను ఉపయోగించాలని సిఫార్సు చేస్తున్నారు." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, fuzzy, python-brace-format #| msgid "A Tor SOCKS port is available on your %(box_name)s on TCP port 9050." msgid "" @@ -6624,40 +6590,40 @@ msgid "" "TCP port 9050." msgstr "టిసిపి పోర్ట్ 9050 పై ఒక టార్ సొక్స్ పోర్ట్ మీ %(box_name)sలో అందుబాటులో ఉంది." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "టార్" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "టోర్ ఉల్లిపాయ సేవ" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "టోర్ సాక్స్ ప్రాతినిధ్య" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "టార్ బ్రిడ్జ్ రిలే" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "టార్ రిలే పోర్ట్ అందుబాటులో ఉంది" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 రవాణా నమోదు చేయబడింది" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 రవాణా నమోదు చేయబడింది" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "టార్ ద్వారా {kind} లో {url} ను ఆక్సెస్ చెయ్యండి" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "టోర్ వాడుకను నిర్ధారించండి{url} టీ సి పి పై{kind}" @@ -6771,13 +6737,13 @@ msgstr "ఉల్లిపాయ సేవ" msgid "Ports" msgstr "పోర్ట్స్" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "అక్రుతీకరణలో ఒక పొరపాటు జరిగింది." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6835,7 +6801,7 @@ msgstr "" msgid "Transmission" msgstr "ట్రాన్స్మిషన్" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -6845,7 +6811,7 @@ msgstr "" "డెస్క్‌టాప్ అప్లికేషన్‌కు దగ్గరగా ఉన్నట్లు భావించేటప్పుడు ఏ ప్రదేశం నుండి అయినా వార్తలను చదవడానికి " "అనుమతించేలా రూపొందించబడింది." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "When enabled, Tiny Tiny RSS can be accessed by any {box_name} లాగిన్‌తో " "వినియోగదారు అయినా సాంగత్యం చేయవచ్చు." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -6865,11 +6831,11 @@ msgstr "" "చిన్న చిన్న RSS కోసం మొబైల్ లేదా డెస్క్‌టాప్ అప్లికేషన్‌ను ఉపయోగిస్తున్నప్పుడు, URLని ఉపయోగించండి/tt-rss-app కలపడం కోసం ." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "టైనీ టైనీ RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "న్యూస్ ఫీడ్ రీడర్" @@ -6877,12 +6843,12 @@ msgstr "న్యూస్ ఫీడ్ రీడర్" msgid "Tiny Tiny RSS (Fork)" msgstr "చిన్న చిన్న RSS (ఫోర్క్)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "తాజా సాఫ్ట్‌వేర్ మరియు భద్రత నవీకరణను కోసం తనిఖీ చేయండి మరియు వర్తించండి." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6894,22 +6860,22 @@ msgstr "" "అందుబాటులో ఉండవు. సిస్టమ్ రీబూట్ అవసరమని భావించినట్లయితే, అది స్వయంచాలకంగా 02:00కి చేయబడుతుంది, " "దీని వలన అన్ని యాప్‌లు క్లుప్తంగా అందుబాటులో ఉండవు." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "సాఫ్ట్‌వేర్ నవీకరణ" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "స్వతంత్ర సాఫ్ట్వేర్ తాజా పరుచడం" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "పంపిణీ నవీకరణను ప్రారంభించడం సాధ్యపడలేదు" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -6918,11 +6884,11 @@ msgstr "" "పంపిణీ నవీకరణను ప్రారంభించడానికి రూట్ విభజనలో తగినంత ఖాళీ స్థలం లేదు. దయచేసి కనీసం 5 GB ఉచితంగా " "ఉండేలా చూసుకోండి. ప్రారంభించబడితే, పంపిణీ నవీకరణ 24 గంటల తర్వాత మళ్లీ ప్రయత్నించబడుతుంది." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "పంపిణీ నవీకరణ ప్రారంభమైంది" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "తదుపరి స్థిరమైన విడుదలకు నవీకరణ ప్రారంభించబడింది. ఇది పూర్తి కావడానికి చాలా సమయం పట్టవచ్చు." @@ -7094,46 +7060,46 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "పంపిణీ మెరుగుపరుచడం ప్రారంభించబడింది" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "గమనింపబడని-నవీకరణలు ఆకృతీకరించునప్పుడు దోషం: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "స్వయంచాలక నవీకరణలు ప్రారంభించబడ్డాయి" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "స్వయంచాలక నవీకరణలు నిలిపివేయబడ్డాయి" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "పంపిణీ మెరుగుపరుచడం ప్రారంభించబడింది" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "పంపిణీ మెరుగుపరుచడం నిలిపివేయబడింది" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "అప్గ్రేడ్ ప్రక్రియ ప్రారంభించబడింది." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "నవీకరణ ప్రారంభం విఫలమైంది." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "తరచుగా ఫీచర్ అప్‌డేట్‌లు యాక్టివేట్ చేయబడ్డాయి." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 #, fuzzy #| msgid "Distribution upgrade enabled" msgid "Starting distribution upgrade test." msgstr "పంపిణీ మెరుగుపరుచడం ప్రారంభించబడింది" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7143,7 +7109,7 @@ msgstr "" "విధానంగా పనిచేస్తాయి. కొన్ని యాప్‌లకు యాప్‌ను యాక్సెస్ చేయడానికి వినియోగదారుని ప్రామాణీకరించడానికి సమూహంలో భాగంగా " "వినియోగదారు ఖాతా అవసరం" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7154,15 +7120,15 @@ msgstr "" "చేయవచ్చు. అయినప్పటికీ, అడ్మిన్ సమూహం యొక్క వినియోగదారులు మాత్రమే యాప్‌లు లేదా సిస్టమ్ " "సెట్టింగ్‌లను మార్చవచ్చు." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "వినియోగదారులు మరియు సమూహాలు" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "అన్ని సేవలకు మరియు సిస్టమ్ అమరికలకు ప్రాప్యత" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP నమోదు \"{search_item}\" తనిఖీ" @@ -7181,21 +7147,21 @@ msgid "" msgstr "" "అవసరం. 150 అక్షరాలు లేదా అంతకంటే తక్కువ. ఆంగ్ల అక్షరాలు, అంకెలు మరియు @/./-/_ మాత్రమే." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "అధికార రహస్యపదం" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "వినియోగదారు కోసం పాస్‌వర్డ్‌ను నమోదు చేయండి\"{user}\"ఖాతా సవరణలకు అధికారం ఇవ్వడానికి." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "చెల్లని రహస్యపదం." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7208,14 +7174,14 @@ msgstr "" "అన్ని సేవలకు లాగిన్ చేయగలరు. వారు SSH ద్వారా సిస్టమ్‌కి లాగిన్ అవ్వగలరు మరియు నిర్వాహక అధికారాలను (సూడో) " "కలిగి ఉంటారు." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" "ల్డప్ వినియోగదారుని సృష్టించడం విఫలమైంది.\n" ".: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, fuzzy, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "సమూహంసమూహానికి కొత్త వినియోగదారుని జోడించడంలో విఫలమైంది: {లోపం {group} {error}" @@ -7234,41 +7200,41 @@ msgstr "" "అవ్వడానికి అనుమతిస్తుంది. మీరు బహుళ కీలను నమోదు చేయవచ్చు, ఒక్కో లైన్‌లో ఒకటి. #తో ప్రారంభమయ్యే ఖాళీ " "పంక్తులు మరియు పంక్తులు విస్మరించబడతాయి." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "ఎల్.డి.ఏ.పి వాడుకరి పేరుమార్పులో విఫలం." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "సమూహంలోంచి వినియోగదారుని తొలగించడంలో విఫలం." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "సమూహంలోకి వినియోగదారుని జోడించడంలో విఫలం." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "SSH కీలను సెట్ చేయడం సాధ్యం కాలేదు." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "వినియోగదారు స్థితిని మార్చడంలో విఫలమైంది." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "ఎల్.డి.ఏ.పి వాడుకరి పాస్‌వర్డ్ మార్పిడి విఫలం." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "నిర్వాహక సమూహానికి కొత్త వినియోగదారుని జోడించడంలో విఫలమైంది: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "కన్సోల్ యాక్సెస్‌ని పరిమితం చేయడంలో విఫలమైంది: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "వాడుకరి ఖాతా సృస్టించబడింది, మీరు లాగిన్ చేయబడ్డారు" @@ -7285,12 +7251,12 @@ msgstr "పాస్‌వర్డ్‌ను సేవ్ చేయి" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "వినియోగదారుని సృష్టించు" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "వినియోగదారుని తొలగించు" @@ -7330,13 +7296,19 @@ msgid "The following administrator accounts exist in the system." msgstr "వ్యవస్థలో కింది నిర్వాహక ఖాతాలు ఉన్నాయి." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "కమాండ్ లైన్ నుండి ఈ ఖాతాలను తొలగించండి మరియు %(box_name)sతో ఉపయోగించగల ఖాతాను సృష్టించడానికి పేజీని " "రిఫ్రెష్ చేయండి. కమాండ్ లైన్‌లో 'echo \"{password}\" | ఆదేశాన్ని అమలు చేయండి /usr/share/plinth/" @@ -7344,7 +7316,7 @@ msgstr "" "ఉపయోగించగలిగితే, ఈ దశను దాటవేయండి." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "వినియోగదారులు" @@ -7377,34 +7349,34 @@ msgstr "" msgid "Save Changes" msgstr "మార్పులను భద్రపరుచు" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "వినియోగదారి %(username)s సృష్టించబడ్డారు." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "వినియోగదారి %(username)s నావీకరించబడ్డాడు." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "వినియోగదారి మార్పు" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "వినియోగదారి {user} తొలగించబడ్డాడు." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "ఎల్.డి.ఏ.పి వినియోగదారి తొలగింపు విఫలం." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "పాస్‌వర్డ్ మార్చు" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "పాస్‌వర్డ్ విజయవంతంగా మార్చబడినది." @@ -7732,7 +7704,7 @@ msgstr "సర్వర్‌కు కనెక్షన్‌ని తొల msgid "Server deleted." msgstr "సర్వర్ తొలగించబడింది." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7745,7 +7717,7 @@ msgstr "" "థీమ్‌లను ఉపయోగించి రూపాన్ని ఎంచుకోవచ్చు. అడ్మినిస్ట్రేషన్ ఇంటర్‌ఫేస్ మరియు ఉత్పత్తి చేయబడిన వెబ్ పేజీలు మొబైల్ " "పరికరాలకు అనుకూలంగా ఉంటాయి." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7758,7 +7730,7 @@ msgstr "" "చేయబడాలి. మీ పేజీలు మరియు పోస్ట్‌లకు మెరుగైన URLల కోసం అడ్మినిస్ట్రేటర్ ఇంటర్‌ఫేస్‌లో పెర్మాలింక్‌లను " "ప్రారంభించండి." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -7768,7 +7740,7 @@ msgstr "" "సృష్టించబడుతుంది. భవిష్యత్తులో అడ్మినిస్ట్రేషన్ ఇంటర్‌ఫేస్‌ను చేరుకోవడానికి అడ్మిన్ పేజీని బుక్‌మార్క్ చేయండి." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -7778,12 +7750,12 @@ msgstr "" "చేయాలి. అదనపు ప్లగిన్‌లు లేదా థీమ్‌లు మీ స్వంత పూచీతో ఇన్‌స్టాల్ చేయబడవచ్చు మరియు మెరుగుపరుచు " "చేయబడవచ్చు." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "వర్డుప్రెస్సు" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "వెబ్‌సైట్ మరియు బ్లాగ్" @@ -7799,7 +7771,7 @@ msgstr "" "సందర్శకులందరినీ అనుమతించండి. నిరుపయోగం చేయడం వలన వర్డుప్రెస్సు సైట్ లేదా బ్లాగును వీక్షించడానికి " "నిర్వాహకులు మాత్రమే అనుమతిస్తుంది. ప్రారంభ వర్డుప్రెస్సు సెటప్ చేసిన తర్వాత మాత్రమే ప్రారంభించండి." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7818,7 +7790,7 @@ msgstr "" "వీక్షణలను ఉపయోగించి ఒక వ్యక్తిని కలిగి ఉన్న అన్ని ఫోటోలు లేదా తేదీలో తీసిన ఫోటోలు లేదా ఒక ప్రదేశంలో తీసిన " "ఫోటోలను కనుగొనడం సులభం. డైరెక్ట్ లింక్‌ని పంపడం ద్వారా వ్యక్తిగత ఫోటోలను ఇతరులతో పంచుకోవచ్చు." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7828,11 +7800,11 @@ msgstr "" "జోఫ్ని సెటప్ చేసిన {box_name} వినియోగదారు కూడా Zophలో నిర్వాహకులు అవుతారు. అదనపు వినియోగదారుల " "కోసం, ఖాతాలు తప్పనిసరిగా {box_name}లో మరియు జోఫ్లో ఒకే వినియోగదారు పేరుతో సృష్టించబడాలి." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "జోఫ్" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "ఫోటో ఆర్గనైజర్" @@ -7885,116 +7857,110 @@ msgstr "" msgid "Finished: {name}" msgstr "సేవ నిలిపివేయబడింది: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "ప్యాకేజీ {package_name} తాజా వెర్షన్ ({latest_version})" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "బ్యాకప్ సమయంలో లోపం" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "వ్యవస్థాపిస్తోంది" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "దిగుమతి అవుతోంది" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "ప్రసార మాధ్యమం మార్పు" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "ఆకృతీకరణ ఫైలు: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "అనువర్తనాలను నిక్షిప్తం చేద్దాం" -#: plinth/setup.py:42 +#: plinth/setup.py:43 #, fuzzy #| msgid "Updating..." msgid "Updating app" msgstr "నవీకరిస్తోంది." -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {string}{details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {string}{details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "అనువర్తనం స్థాపించబడింది." -#: plinth/setup.py:87 +#: plinth/setup.py:88 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "చివరి నవీకరణ" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "అనువర్తనాలను నిక్షిప్తం చేద్దాం" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {string}{details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "అనువర్తనం స్థాపించబడింది." -#: plinth/setup.py:451 +#: plinth/setup.py:452 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8053,53 +8019,54 @@ msgstr "నిక్షిప్తం" msgid "Service %(service_name)s is not running." msgstr "%(service_name)s సేవ నడవడం లేదు." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "%(box_name)s కోసం కోర్ ఫంక్షనాలిటీ మరియు వెబ్ ఇంటర్‌ఫేస్" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " నివాసం" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "ముంగిలి" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " కార్యక్షేత్రం" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "అనువర్తనాలు" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " కార్యవ్యవస్థ" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "వ్యవస్థ" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "రహస్యపదాన్ని మార్చు" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "మూసివేయి" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "నిష్క్రమించు" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "బాషను ఎంచుకోండి" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "లోనికి ప్రవేశించండి" @@ -8385,6 +8352,74 @@ msgstr "" msgid "Gujarati" msgstr "గుజరాతీ" +#~ msgid "Enable DNSSEC" +#~ msgstr "DNSSEC అమలుచెయ్యి" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "డొమైన్ నేమ్ సిస్టం భద్రతా పొడిగింపు ని ప్రారంభించండి" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "ఫైర్‌వాల్ డెమోన్ రన్ కావడం లేదు. దయచేసి దీన్ని అమలు చేయండి. %(box_name)sలో ఫైర్‌వాల్ డిఫాల్ట్‌గా " +#~ "ప్రారంభించబడింది. ఏదైనా డెబియన్ ఆధారిత సిస్టమ్‌లో (%(box_name)s వంటివి) మీరు 'సర్వీస్ ఫైర్‌వాల్డ్ " +#~ "స్టార్ట్' కమాండ్‌ని ఉపయోగించి లేదా systemd 'systemctl start firewalld' ఉన్న సిస్టమ్ విషయంలో " +#~ "దీన్ని అమలు చేయవచ్చు." + +#~ msgid "Migrate to ECC" +#~ msgstr "ECCకి మైగ్రేట్ చేయండి" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "మీ OpenVPN ఇన్‌స్టాలేషన్ ప్రస్తుతం RSAని ఉపయోగిస్తోంది. ఆధునిక ఎలిప్టిక్ కర్వ్ క్రిప్టోగ్రఫీకి మారడం " +#~ "కనెక్షన్ మరియు భద్రతను ఏర్పాటు చేసే వేగాన్ని మెరుగుపరుస్తుంది. ఈ ఆపరేషన్ కోలుకోలేనిది. చాలా సింగిల్ " +#~ "బోర్డ్ కంప్యూటర్‌లలో దీనికి కొన్ని నిమిషాలు మాత్రమే పడుతుంది." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "%(box_name)sలో OpenVPN యొక్క అన్ని కొత్త ఇన్‌స్టాలేషన్‌లు డిఫాల్ట్‌గా ECCని ఉపయోగిస్తాయి. వీలైనంత " +#~ "త్వరగా వలస వెళ్లాలని మేము సిఫార్సు చేస్తున్నాము." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "హెచ్చరిక: ఈ ఆపరేషన్ ద్వారా ఇప్పటికే ఉన్న క్లయింట్ ప్రొఫైల్‌లు చెల్లుబాటు కావు. " +#~ "%(box_name)sలోని OpenVPN వినియోగదారులందరూ తప్పనిసరిగా వారి కొత్త ప్రొఫైల్‌లను డౌన్‌లోడ్ చేసుకోవాలి. ఈ " +#~ "సర్వర్‌కి కనెక్ట్ చేయడానికి ECCకి అనుకూలమైన OpenVPN క్లయింట్‌లను ఉపయోగించాలి." + +#~ msgid "Migrate" +#~ msgstr "మోడిగ్రేట్ చేయండి" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "SSH ప్రమాణీకరణ తో SSH ఆపివేయబడింది ." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "SSH ప్రమాణీకరణ తో SSH ఆపివేయబడింది ." + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "బ్యాకప్ సమయంలో లోపం" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "%(box_name)s కోసం కోర్ ఫంక్షనాలిటీ మరియు వెబ్ ఇంటర్‌ఫేస్" + #~ msgid "Network Connections" #~ msgstr "నెట్వర్క్ అనుసంధానాలు" diff --git a/plinth/locale/tr/LC_MESSAGES/django.po b/plinth/locale/tr/LC_MESSAGES/django.po index 92ecefd55..eaae6acff 100644 --- a/plinth/locale/tr/LC_MESSAGES/django.po +++ b/plinth/locale/tr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: Oğuz Ersen \n" "Language-Team: Turkish calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1037,23 +1030,23 @@ msgstr "" "erişebilecektir. Erişimi olan tüm kullanıcılar tüm kütüphaneleri " "kullanabilir." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "calibre e-kitap kütüphanesini kullan" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "E-kitap Kütüphanesi" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Yeni kütüphanenin adı" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1061,7 +1054,7 @@ msgstr "" "Boşluklar veya özel karakterler olmadan sadece İngiliz alfabesi harfleri, " "sayılar ve _ . ve - karakterleri. Örnek: Kutuphanem_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Bu ada sahip bir kütüphane zaten var." @@ -1109,20 +1102,20 @@ msgstr "%(library)s kütüphanesine git" msgid "Delete library %(library)s" msgstr "%(library)s kütüphanesini sil" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Kütüphane oluşturuldu." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Kütüphane oluşturulurken bir hata meydana geldi." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} silindi." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "{name} silinemedi: {error}" @@ -1170,7 +1163,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Sunucu Yönetimi" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1178,18 +1171,18 @@ msgstr "" "Burada anamakine adı, etki alanı adı, web sunucusu ana sayfası vb. gibi bazı " "genel yapılandırma seçeneklerini ayarlayabilirsiniz." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Genel Yapılandırma" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Yapılandır" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1304,47 +1297,47 @@ msgstr "" "Günlükler, sisteme kimin eriştiği ve çeşitli hizmetlerden gelen hata " "ayıklama bilgileri hakkında bilgiler içerir" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Anamakine adı ayarlanırken hata oldu: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Anamakine adı ayarlandı" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Etki alanı adı ayarlanırken hata oldu: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Etki alanı adı ayarlandı" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Web sunucusu ana sayfası ayarlanırken hata oldu: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Web sunucusu ana sayfası ayarlandı" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Gelişmiş kip değiştirilirken hata oldu: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Gelişmiş uygulamalar ve özellikler gösteriliyor" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Gelişmiş uygulamalar ve özellikler gizleniyor" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1356,7 +1349,7 @@ msgstr "" "SIP ve diğer iletişim sunucuları, başka şekilde birbirleriyle bağlantı " "kuramayan taraflar arasında bir çağrı kurmak için bunu kullanabilir." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse veya ejabberd gibi " "sunucuların burada sağlanan ayrıntılarla yapılandırılması gerekir." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP Yardımcısı" @@ -1428,11 +1421,11 @@ msgstr "Saat dilimi ayarlanırken hata oldu: {exception}" msgid "Time zone set" msgstr "Saat dilimi ayarlandı" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge, bir Web kullanıcı arayüzüne sahip bir BitTorrent istemcisidir." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1440,16 +1433,16 @@ msgstr "" "Varsayılan parola 'deluge'dir, ancak bu hizmeti etkinleştirdikten hemen " "sonra oturum açmalı ve parolayı değiştirmelisiniz." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "BitTorrent uygulamalarını kullanarak dosyaları indir" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent Web İstemcisi" @@ -1576,7 +1569,7 @@ msgstr "Sonuç" msgid "Diagnostic Test" msgstr "Tanı Denemesi" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1588,7 +1581,7 @@ msgstr "" "başkalarının bu {box_name} tarafından sağlanan hizmetleri bulmasını " "engelleyecektir." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1605,7 +1598,7 @@ msgstr "" "sunucu DNS adınızı yeni IP'ye atayacaktır ve İnternet'ten birisi sizin DNS " "adınızı sorarsa, şu anki IP adresinizle bir yanıt alacaktır." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1618,11 +1611,11 @@ msgstr "" "freedns.afraid." "org adresinde bulabilirsiniz." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Değişken DNS İstemcisi" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Değişken Etki Alanı Adı" @@ -1751,7 +1744,7 @@ msgstr "Bu alan gereklidir." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1806,7 +1799,7 @@ msgstr "Sunucu bağlantıyı reddetti" msgid "Already up-to-date" msgstr "Zaten güncel" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1814,7 +1807,7 @@ msgstr "" "XMPP, açık ve standartlaştırılmış bir iletişim protokolüdür. Burada ejabberd " "adı verilen XMPP sunucunuzu çalıştırabilir ve yapılandırabilirsiniz." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client{box_name} oturum " "açma adı ile herhangi bir kullanıcı tarafından erişilebilir." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn uygulamasını yükleyin veya harici " "bir sunucu yapılandırın." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Sohbet Sunucusu" @@ -1970,7 +1963,7 @@ msgstr "" "Etki alanınızı sistemde Yapılandır sayfasında " "ayarlayabilirsiniz." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1980,7 +1973,7 @@ msgstr "" "Postfix e-posta gönderir ve alır. Dovecot, e-posta istemcilerinin IMAP ve " "POP3 kullanarak posta kutunuza erişmesini sağlar. Rspamd spam ile ilgilenir." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1992,7 +1985,7 @@ msgstr "" "giden e-postaları da kısıtlar. Bazıları, açık bir istekten sonra kısıtlamayı " "kaldırır. Daha fazla bilgi için kılavuz sayfasına bakın." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2007,7 +2000,7 @@ msgstr "" "ekleyebilirler. \"Postmaster\" gibi gerekli kod adları, ilk yönetici " "kullanıcıyı işaret ederek otomatik olarak oluşturulur." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2015,7 +2008,7 @@ msgstr "" "Roundcube uygulaması, kullanıcıların " "e-postaya erişmesi için web arayüzü sağlar." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2145,7 +2138,7 @@ msgstr "Bağlantı noktası" msgid "Host/Target/Value" msgstr "Anamakine/Hedef/Değer" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2157,7 +2150,7 @@ msgstr "" "ve uygun şekilde yapılandırılmış halde tutulması, İnternet kaynaklı güvenlik " "tehdidi riskini azaltır." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Güvenlik Duvarı" @@ -2177,53 +2170,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Harici ağlar için {name} ({details}) bağlantı noktası kullanılamaz" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Güvenlik duvarı arka plan programı çalışmıyor. Lütfen çalıştırın. Güvenlik " -"duvarı varsayılan olarak %(box_name)s ile etkinleştirilmiş gelir. Herhangi " -"bir Debian tabanlı sistemde (%(box_name)s gibi), 'service firewalld start' " -"komutunu kullanarak veya systemd 'systemctl start firewalld' olan bir sistem " -"durumunda çalıştırabilirsiniz." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Hizmet/Bağlantı Noktası" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Etkinleştirildi" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Etkisizleştirildi" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "İzin Verildi" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "İzin Verildi (sadece dahili)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "İzin Verildi (sadece harici)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Engellendi" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2233,13 +2212,13 @@ msgstr "" "buna güvenlik duvarında da izin verilir ve bir hizmeti " "etkisizleştirdiğinizde, güvenlik duvarında da etkisizleştirilir." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Gelişmiş" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2293,7 +2272,7 @@ msgstr "Kurulumu Başlat" msgid "Setup Complete" msgstr "Kurulum Tamamlandı" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2311,7 +2290,7 @@ msgstr "" "depoları çoğaltabilir ve kod değişikliklerini yükleyebilirsiniz. Ve kodunuzu " "dünyanın her yerinden insanlarla paylaşabilirsiniz." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2319,68 +2298,68 @@ msgstr "" "Git'in nasıl kullanılacağı hakkında daha fazla bilgi edinmek için Git öğreticisini ziyaret edin." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Git depolarına okuma-yazma erişimi" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Basit Git Barındırma" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Geçersiz depo URL'si." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Geçersiz depo adı." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Varolan bir depoyu içe aktarmak için yeni bir deponun veya URL'nin adı." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Deponun açıklaması" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Gitweb'de görüntülemek için isteğe bağlı." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Depo sahibinin adı" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Özel depo" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Sadece yetkili kullanıcıların bu arşive erişmesine izin verir." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Bu ada sahip bir depo zaten var." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Deponun adı" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "Bir depoyu benzersiz şekilde tanımlayan alfa sayısal bir dizgi." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Varsayılan dal" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb bunu varsayılan dal olarak görüntüler." @@ -2424,19 +2403,19 @@ msgstr "%(name)s Git Deposunu Sil" msgid "Delete this repository permanently?" msgstr "Bu depo kalıcı olarak silinsin mi?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Depo oluşturuldu." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Depo oluşturulurken bir hata meydana geldi." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Depo düzenlendi." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Depoyu düzenle" @@ -2797,7 +2776,7 @@ msgstr "{box_name} Hakkında" msgid "{box_name} Manual" msgstr "{box_name} Kılavuzu" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2809,7 +2788,7 @@ msgstr "" "olarak işletilen bir ağ aracılığıyla şifreli trafik göndererek isim " "gizliliği sağlar." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2817,26 +2796,26 @@ msgstr "" "I2P hakkında daha fazla bilgiyi proje ana sayfasında bulabilirsiniz." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" "Sağlanan web arayüzüne ilk ziyaret, yapılandırma işlemini başlatacaktır." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "I2P uygulamasını yönet" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "İsim Gizliliği Ağı" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P Vekil Sunucusu" @@ -2882,7 +2861,7 @@ msgstr "" "uygulama sağlar. Dosyaları torrent'leri ekleyerek indirin veya bir dosyayı " "paylaşmak için yeni bir torrent oluşturun." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2892,7 +2871,7 @@ msgstr "" "birkaç hafif biçimlendirme dilini, yorumlar ve RSS bildirimleri gibi ortak " "blog oluşturma işlevselliğini destekler." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2906,15 +2885,15 @@ msgstr "" "href=\"{users_url}\">Kullanıcı Yapılandırmasında bu izinleri " "değiştirebilir veya yeni kullanıcılar ekleyebilirsiniz." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Viki ve Blog" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Viki uygulamalarını görüntüle ve düzenle" @@ -2970,43 +2949,43 @@ msgstr "" "Bu eylem düzeltim geçmişi dahil olmak üzere tüm yazıları, sayfaları ve " "yorumları silecek. Bu viki ya da blog kalıcı olarak silinsin mi?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "{name} viki oluşturuldu." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Viki oluşturulamadı: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "{name} blog oluşturuldu." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Blog oluşturulamadı: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} silindi." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "{title} silinemedi: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" "infinoted, işbirliğine dayalı bir metin düzenleyici olan Gobby için bir " "sunucudur." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3017,11 +2996,11 @@ msgstr "" "istemcisini indirin ve yükleyin. Ardından Gobby'yi başlatın, \"Sunucuya " "Bağlan\" seçeneğini seçin ve {box_name} cihazınızın etki alanı adını girin." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby Sunucusu" @@ -3069,7 +3048,7 @@ msgstr "Janus Video Odası" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "JavaScript lisans bilgileri" @@ -3089,7 +3068,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Sohbet İstemcisi" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3105,7 +3084,7 @@ msgstr "" "(CA) olan Let's Encrypt'a bir etki alanının sahibi olduğunu kanıtlayarak " "yapar." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3117,15 +3096,15 @@ msgstr "" "Lütfen bu hizmeti kullanmadan önce Let's Encrypt Abone Sözleşmesini okuyun ve kabul edin." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Sertifikalar" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Denenemiyor: Hiçbir etki alanı yapılandırılmamış." @@ -3190,7 +3169,7 @@ msgstr "" "Hiçbir etki alanı yapılandırılmadı. Bunlar için sertifika alabilmek amacıyla " "etki alanlarını yapılandırın." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3199,34 +3178,34 @@ msgstr "" "{domain} etki alanı için sertifika başarılı olarak iptal edildi. Bunun " "etkili olması birkaç dakika alabilir." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "{domain} etki alanı için sertifika iptal etme başarısız oldu: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "{domain} etki alanı için sertifika başarılı olarak elde edildi" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "{domain} etki alanı için sertifika elde etme başarısız oldu: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "{domain} etki alanı için sertifika başarılı olarak silindi" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "{domain} etki alanı için sertifika silme başarısız oldu: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3243,7 +3222,7 @@ msgstr "" "kullanıcılar, federasyon aracılığıyla diğer tüm Matrix sunucularındaki " "kullanıcılarla sohbet edebilir." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3253,7 +3232,7 @@ msgstr "" "ihtiyaç duyar. Coturn uygulamasını yükleyin veya " "harici bir sunucu yapılandırın." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3360,7 +3339,7 @@ msgstr "" "sertifikası gerekir. Bir tane edinmek için lütfen Let's Encrypt'a gidin." -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3373,7 +3352,7 @@ msgstr "" "barındırmak, notlar almak veya projelerde arkadaşlarınızla işbirliği yapmak " "için kullanabilirsiniz." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3388,7 +3367,7 @@ msgstr "" "giderek MediaWiki'nin kendisinden daha fazla kullanıcı hesabı " "oluşturabilirsiniz." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3396,12 +3375,12 @@ msgstr "" "Bu viki'ye bağlantısı olan herkes bunu okuyabilir. Sadece oturum açmış " "kullanıcılar içerikte değişiklik yapabilir." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Viki" @@ -3483,35 +3462,35 @@ msgstr "Parola güncellendi" msgid "Password update failed. Please choose a stronger password" msgstr "Parola güncelleme başarısız oldu. Lütfen daha güçlü bir parola seçin" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Herkese açık kayıtlar etkinleştirildi" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Herkese açık kayıtlar etkisizleştirildi" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Özel kip etkinleştirildi" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Özel kip etkisizleştirildi" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Varsayılan kaplama değiştirildi" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Etki alanı adı güncellendi" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Site adı güncellendi" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3524,11 +3503,11 @@ msgstr "" "(30000) çalıştırılmasını sağlar. Sunucuya bağlanmak için bir Minetest istemcisi gereklidir." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Blok Kum Havuzu" @@ -3580,7 +3559,7 @@ msgstr "" msgid "Address" msgstr "Adres" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3767,7 +3746,7 @@ msgstr "Güvenli Kabuk" msgid "Services" msgstr "Hizmetler" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3775,7 +3754,7 @@ msgstr "" "Ağ cihazlarını yapılandırın. İnternet'e Ethernet, Wi-Fi veya PPPoE ile " "bağlanın. Bu bağlantıyı ağdaki diğer cihazlarla paylaşın." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3783,7 +3762,7 @@ msgstr "" "Diğer yöntemler aracılığıyla yönetilen cihazlar burada yapılandırma için " "mevcut olmayabilir." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Ağlar" @@ -4217,7 +4196,7 @@ msgstr "Bağlantıyı düzenle" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Düzenle" @@ -4322,7 +4301,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Yöntem" @@ -4338,7 +4317,7 @@ msgstr "DNS sunucusu" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Varsayılan" @@ -4351,7 +4330,7 @@ msgid "This connection is not active." msgstr "Bu bağlantı etkin değil." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Güvenlik" @@ -4934,7 +4913,7 @@ msgstr "{name} bağlantısı silindi." msgid "Failed to delete connection: Connection not found." msgstr "Bağlantının silinmesi başarısız oldu: Bağlantı bulunamadı." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4951,20 +4930,20 @@ msgstr "" "isim gizliliği sayesinde {box_name} aracılığıyla İnternet'e de " "erişebilirsiniz." -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "VPN hizmetlerine bağlan" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Sanal Özel Ağ" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4974,57 +4953,21 @@ msgstr "Profili İndir" msgid "Tunnelblick" msgstr "Tunnelblick" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "ECC'ye Geçir" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" -"OpenVPN kurulumunuz şu anda RSA kullanıyor. Modern Eliptik Eğri " -"Şifrelemesine geçiş, bağlantı kurma hızını ve güvenliği artırır. Bu işlem " -"geri alınamaz. Çoğu tek kartlı bilgisayarda sadece birkaç dakika sürmektedir." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" -"%(box_name)s cihazındaki tüm yeni OpenVPN kurulumları, varsayılan olarak " -"ECC'yi kullanacaktır. Mümkün olan en kısa sürede geçiş yapmanızı öneririz." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" -"Uyarı: Varolan istemci profilleri bu işlem tarafından geçersiz " -"kılınacaktır. %(box_name)s cihazındaki tüm OpenVPN kullanıcıları yeni " -"profillerini indirmek zorundadır. Bu sunucuya bağlanmak için ECC ile uyumlu " -"OpenVPN istemcileri kullanılmalıdır." - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "Geçir" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Profil" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "%(box_name)s cihazının VPN'ine bağlanmak için bir profil indirmeniz ve bunu " @@ -5033,16 +4976,17 @@ msgstr "" "bunların nasıl yapılandırılacağıyla ilgili talimatlar için yukarıdaki \"Daha " "fazla bilgi edinin...\" bağlantısına tıklayın." -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "Profil, %(box_name)s cihazının her kullanıcısına özgüdür. Gizli tutun." -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Profilimi indir" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -5055,17 +4999,17 @@ msgstr "" "{box_name} hizmetlerinize İnternet'ten erişilemiyorsa ihtiyacınız vardır. " "Bu, aşağıdaki durumları içerir:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} kısıtlanmış bir güvenlik duvarının arkasında." -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "{box_name} denetleyemediğiniz bir (kablosuz) yönlendiriciye bağlı." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -5073,7 +5017,7 @@ msgstr "" "İSS'niz size bir dış IP adresi sağlamıyor ve bunun yerine NAT aracılığıyla " "İnternet bağlantısı sağlıyor." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -5081,11 +5025,11 @@ msgstr "" "İSS'niz size bir sabit IP adresi sağlamıyor ve IP adresiniz İnternet'e her " "bağlandığınızda değişiyor." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "İSS'niz gelen bağlantıları sınırlıyor." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -5099,23 +5043,23 @@ msgstr "" "href=\"https://pagekite.net\">pagekite.net. Gelecekte bunun için " "arkadaşınızın {box_name} cihazını kullanmak mümkün olabilir." -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Herkese Açık Görünürlük" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite Etki Alanı" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Sunucu etki alanı" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5123,31 +5067,31 @@ msgstr "" "Pagekite sunucunuzu seçin. Varsayılan pagekite.net sunucusunu kullanmak için " "\"pagekite.net\" olarak ayarlayın." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Sunucu bağlantı noktası" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Pagekite sunucunuzun bağlantı noktası (varsayılan: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite adı" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Örnek: benimkutum.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Geçersiz kite adı" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite gizli anahtarı" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." @@ -5155,35 +5099,35 @@ msgstr "" "Kite ile ilişkilendirilmiş bir gizli anahtar ya da kite üzerinde hiçbir " "gizli anahtar ayarlanmamışsa hesabınız için varsayılan gizli anahtar." -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "protokol" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "harici (ön uç) bağlantı noktası" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "dahili (freedombox) bağlantı noktası" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Alt Etki Alanlarını etkinleştir" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Özel hizmet silindi" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Bu hizmet zaten standart bir hizmet olarak mevcut." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Özel hizmet eklendi" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Bu hizmet zaten var" @@ -5221,32 +5165,32 @@ msgstr "" "dışındaki bağlantı noktalarında HTTPS'nin sorunlara neden olduğu " "bilinmektedir." -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Web Sunucusu (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" "Site http://{0} adresinde kullanılabilir olacaktır" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Web Sunucusu (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" "Site https://{0} adresinde kullanılabilir " "olacaktır" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Güvenli Kabuk (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5298,8 +5242,8 @@ msgstr "" "Şu anda bir kurulum veya yükseltme çalışıyor. Kapatmadan veya yeniden " "başlatmadan önce bitene kadar beklemeyi düşünün." -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Yeniden başlat" @@ -5349,6 +5293,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Şimdi Kapat" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5390,7 +5367,7 @@ msgstr "Web Vekil Sunucusu" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Tcp{kind} üzerinde {proxy} vekil sunucusu ile {url} adresine erişin" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5407,7 +5384,7 @@ msgstr "" "çalıştırabilir ve bir masaüstünden veya cep telefonundan bir veya daha fazla " "Quassel istemcisini bağlamak ve bağlantısını kesmek için kullanılabilir." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your masaüstü ve mobil cihazlarınızdan bağlanacak istemciler mevcuttur." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC İstemcisi" @@ -5431,7 +5408,7 @@ msgstr "IRC İstemcisi" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5446,7 +5423,7 @@ msgstr "" "\">desteklenen bir istemci uygulaması gereklidir. Radicale'ye {box_name} " "oturum açma adı ile herhangi bir kullanıcı tarafından erişilebilir." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " @@ -5456,12 +5433,12 @@ msgstr "" "temel bir web arayüzü sağlar. Ayrı bir istemci kullanılarak yapılması " "zorunlu olan olayların veya kişilerin eklenmesini desteklemez." -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Takvim ve Adres Defteri" @@ -5536,7 +5513,7 @@ msgstr "" "kullanıcı adınızı girin. Ara düğmesine tıklamak, varolan takvimleri ve adres " "defterlerini listeleyecektir." -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Erişim izinleri yapılandırması güncellendi" @@ -5628,7 +5605,7 @@ msgstr "" "RSS ile RSS-Bridge'i kullanabilirsiniz. Bir bildirim eklerken, kimlik " "doğrulamayı etkinleştirin ve {box_name} kimlik bilgilerinizi kullanın." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Haber bildirimlerini oku ve abone ol" @@ -5641,7 +5618,7 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "RSS Bildirim Oluşturucu" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." @@ -5649,7 +5626,7 @@ msgstr "" "Samba, FreedomBox ile yerel ağınızdaki diğer bilgisayarlar arasında dosya ve " "klasör paylaşmayı sağlar." -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5663,11 +5640,11 @@ msgstr "" "(Linux ve Mac'te) konumunda erişilebilir. Aralarından seçim yapabileceğiniz " "üç tür paylaşım vardır: " -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "Açık paylaşım - yerel ağınızdaki herkes tarafından erişilebilir." -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." @@ -5675,7 +5652,7 @@ msgstr "" "Grup paylaşımı - sadece Freedombox paylaşım grubundaki FreedomBox " "kullanıcıları tarafından erişilebilir." -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." @@ -5683,15 +5660,15 @@ msgstr "" "Ev paylaşımı - Freedombox paylaşım grubundaki her kullanıcı kendi özel " "alanına sahip olabilir." -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Özel paylaşımlara erişim" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Ağ Dosya Depolama" @@ -5778,15 +5755,15 @@ msgstr "Paylaşım adı" msgid "Action" msgstr "Eylem" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox OS disk" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "Açık Paylaşım" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "Grup Paylaşımı" @@ -5812,7 +5789,7 @@ msgstr "Paylaşım etkisizleştirildi." msgid "Error disabling share: {error_message}" msgstr "Paylaşımı etkisizleştirirken hata oldu: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5820,7 +5797,7 @@ msgstr "" "Searx, gizliliğe saygılı bir İnternet üstbilgi arama motorudur. Birden çok " "arama motorundan gelen sonuçları toplar ve görüntüler." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5828,39 +5805,39 @@ msgstr "" "Searx, arama motorları tarafından izlenmeyi ve profil oluşturmayı önlemek " "için kullanılabilir. Varsayılan olarak hiçbir tanımlama bilgisi saklamaz." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Web'de ara" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Web Arama" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Güvenli Arama" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "Arama sonuçlarınıza uygulanacak varsayılan aile süzgecini seçin." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Orta" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Sıkı" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Herkese Açık Erişime izin ver" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Bu uygulamanın, ona ulaşabilen herkes tarafından kullanılmasına izin verin." @@ -6042,7 +6019,7 @@ msgstr "Yer İşaretleri" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " @@ -6052,7 +6029,7 @@ msgstr "" "bir SOCKS5 vekil sunucusudur. İnternet süzmeyi ve sansürü atlamak için " "kullanılabilir." -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -6065,7 +6042,7 @@ msgstr "" "Yerel cihazlar bu vekil sunucuya bağlanabilir ve verileri şifrelenecek ve " "Shadowsocks sunucusu aracılığıyla vekil sunucuya tabi tutulacaktır." -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" @@ -6074,42 +6051,42 @@ msgstr "" "uygulamanızda SOCKS5 vekil sunucu URL'sini http://freedombox_adresi:1080/ " "olarak ayarlayın" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "Shadowsocks" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Socks5 Vekil Sunucusu" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Önerilen" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Sunucu" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Sunucu anamakine adı veya IP adresi" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Sunucu bağlantı noktası numarası" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Verileri şifrelemek için kullanılan parola. Sunucu parolası ile eşleşmek " "zorundadır." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Şifreleme yöntemi. Sunucudaki ayarla eşleşmek zorundadır." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -6118,15 +6095,15 @@ msgstr "" "Paylaşım, web üzerinden {box_name} cihazınızdaki dosyaları ve klasörleri, " "seçilen kullanıcı gruplarıyla paylaşmanızı sağlar." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Paylaşım" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Paylaşım adı" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -6134,27 +6111,27 @@ msgstr "" "Bir paylaşımı benzersiz şekilde tanımlayan küçük harfli alfa-sayısal bir " "dizgi. Örnek: ortam." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Paylaşma yolu" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Bu sunucudaki paylaşmayı düşündüğünüz bir klasörün disk yolu." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Herkese açık paylaşım" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Bu klasördeki dosyaları bağlantıya sahip herkesin kullanımına açın." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Paylaşımdaki dosyaları okuyabilen kullanıcı grupları:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." @@ -6162,11 +6139,11 @@ msgstr "" "Seçilen kullanıcı gruplarının kullanıcıları paylaşımdaki dosyaları " "okuyabilecektir." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Bu ada sahip bir paylaşım zaten var." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "Paylaşımlar herkese açık olmalı veya en az bir grupla paylaşılmalıdır" @@ -6203,19 +6180,19 @@ msgstr "Paylaşım eklendi." msgid "Add Share" msgstr "Paylaşım Ekleyin" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Paylaşım düzenlendi." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Paylaşımı Düzenle" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Paylaşım silindi." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6226,7 +6203,7 @@ msgstr "" "durumunda sistemi önceden bilinen iyi bir duruma geri döndürmek için " "kullanılabilir." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6238,7 +6215,7 @@ msgstr "" "eski anlık görüntüler, aşağıdaki ayarlara göre otomatik olarak " "temizlenecektir." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for yedeklemelerin " "yerine geçmez. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Depolama Anlık Görüntüleri" @@ -6352,7 +6329,7 @@ msgstr "Tarih" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Anlık Görüntüleri Sil" @@ -6406,58 +6383,58 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "#%(number)s Nolu Anlık Görüntüye Geri Al" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "el ile oluşturuldu" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "zaman çizelgesi" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Anlık Görüntüleri Yönet" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Anlık görüntü oluşturuldu." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Depolama anlık görüntü yapılandırması güncellendi" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Eylem hatası: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Seçilen anlık görüntüler silindi" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Anlık görüntü şu anda kullanımda. Lütfen daha sonra tekrar deneyin." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "#{number} nolu anlık görüntüye geri alındı." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" "Geri alma işlemini tamamlamak için sistem yeniden başlatılmak zorundadır." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "Anlık Görüntüye Geri Al" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6469,7 +6446,7 @@ msgstr "" "bağlantıları kullanarak yönetim görevlerini gerçekleştirebilir, dosyaları " "kopyalayabilir veya diğer hizmetleri çalıştırabilir." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Güvenli Kabuk (SSH) Sunucusu" @@ -6507,14 +6484,6 @@ msgstr "Algoritma" msgid "Fingerprint" msgstr "Parmak İzi" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "Parola ile SSH kimlik doğrulaması etkisizleştirildi." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "Parola ile SSH kimlik doğrulaması etkinleştirildi." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "Tek Oturum Açma" @@ -6527,7 +6496,7 @@ msgstr "Oturum aç" msgid "Logged out successfully." msgstr "Başarılı olarak oturumu kapatıldı." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6539,105 +6508,105 @@ msgstr "" "ortamı bağlayabilir ve bağlantısını kaldırabilir, kök bölümünü vb. " "genişletebilirsiniz." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Depolama" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} bayt" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "İşlem başarısız oldu." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "İşlem iptal edildi." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Aygıtın zaten bağlantısı kaldırılıyor." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "Eksik sürücü/araç desteğinden dolayı işlem desteklenmiyor." -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "İşlem zaman aşımına uğradı." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "İşlem, derin uyku durumunda olan bir diski uyandırır." -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Meşgul olan bir aygıtın bağlantısı kaldırılmaya çalışılıyor." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "İşlem zaten iptal edildi." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "İstenen işlemi gerçekleştirmek için yetkili değilsiniz." -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Aygıt zaten bağlı." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Aygıt bağlı değil." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "İstenen seçeneği kullanmak için izin verilmedi." -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Aygıt başka bir kullanıcı tarafından bağlandı." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Sistem bölümünde düşük alan: %{percent_used} kullanıldı, {free_space} boş." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Düşük disk alanı" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "Disk arızası yakın" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " @@ -6646,39 +6615,39 @@ msgstr "" "Disk {id}, yakın gelecekte başarısız olma ihtimalinin yüksek olduğunu " "bildiriyor. Hala yapabilirken tüm verileri kopyalayın ve sürücüyü değiştirin." -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Geçersiz dizin adı." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Dizin mevcut değil." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Yol bir dizin değil." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Dizin kullanıcı tarafından okunabilir değil." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Dizin kullanıcı tarafından yazılabilir değil." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Dizin" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Alt dizin (isteğe bağlı)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "Paylaş" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Diğer dizin (aşağıda belirtin)" @@ -6715,7 +6684,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Kök Bölümünü Genişlet" @@ -6738,30 +6707,30 @@ msgstr "" "%(expandable_root_size)s ek boş alan kök bölümünüzde kullanılabilir " "olacaktır." -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Bölüm genişletilirken hata oldu: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Bölüm başarılı olarak genişletildi." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} güvenle çıkarılabilir." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Aygıt güvenli bir şekilde çıkarılabilir." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Aygıt çıkarılırken hata oldu: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6773,7 +6742,7 @@ msgstr "" "dosyaların oluşturulması, değiştirilmesi veya silinmesi, Syncthing'i de " "çalıştıran diğer tüm cihazlarda otomatik olarak tekrarlanacaktır." -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6792,20 +6761,20 @@ msgstr "" "{box_name} cihazındaki web arayüzü sadece \"admin\" veya \"syncthing-access" "\" grubuna ait kullanıcılar tarafından kullanılabilir." -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Syncthing uygulamasını yönet" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Dosya Eşitleme" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6818,7 +6787,7 @@ msgstr "" "gezinirken en iyi koruma için Tor Projesi, Tor Tarayıcı kullanmanızı önerir." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6827,40 +6796,40 @@ msgstr "" "9050 nolu TCP bağlantı noktası üzerindeki dahili ağlar için {box_name} " "cihazınızda bir Tor SOCKS bağlantı noktası kullanılabilir." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor Onion Hizmeti" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "Tor Socks Vekil Sunucusu" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor Köprüsü Aktarımı" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor aktarımı bağlantı noktası kullanılabilir" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "Obfs3 taşıma kayıtlı" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "Obfs4 taşıma kayıtlı" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Tor aracılığıyla tcp{kind} üzerinde erişim URL'si {url}" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Tcp{kind} üzerinde {url} adresinde Tor kullanımını onaylama" @@ -6980,11 +6949,11 @@ msgstr "Onion Hizmeti" msgid "Ports" msgstr "Bağlantı Noktaları" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Yapılandırma güncelleniyor" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Uygulama yapılandırılırken hata oldu: {error}" @@ -7048,7 +7017,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -7058,7 +7027,7 @@ msgstr "" "hissettiren herhangi bir konumdan haberleri okumayı sağlamak için " "tasarlanmış bir haber bildirim (RSS/Atom) okuyucusu ve toplayıcısıdır." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -7067,7 +7036,7 @@ msgstr "" "Etkinleştirildiğinde Tiny Tiny RSS'ye, bildirim okuyucu grubuna ait herhangi bir kullanıcı tarafından erişilebilir." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -7075,11 +7044,11 @@ msgstr "" "Tiny Tiny RSS için bir mobil veya masaüstü uygulaması kullanırken, bağlanmak " "için /tt-rss-app URL'sini kullanın." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Haber Bildirim Okuyucusu" @@ -7087,12 +7056,12 @@ msgstr "Haber Bildirim Okuyucusu" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (Fork)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "En son yazılım ve güvenlik güncellemelerini denetleyin ve uygulayın." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -7105,22 +7074,22 @@ msgstr "" "Eğer sistemin yeniden başlatılması gerekli görülürse, saat 02:00'da otomatik " "olarak yapılır ve tüm uygulamalar kısa bir süre için kullanılamaz hale gelir." -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Yazılım Güncellemesi" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox Güncellendi" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Dağıtım güncellemesi başlatılamadı" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " @@ -7130,11 +7099,11 @@ msgstr "" "Lütfen en az 5 GB boş alan olduğundan emin olun. Dağıtım güncellemesi, " "etkinleştirildiyse 24 saat sonra yeniden denenecektir." -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Dağıtım güncellemesi başlatıldı" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7313,44 +7282,44 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Dağıtım yükseltmesini şimdi dene" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "unattended-upgrades yapılandırılırken bir hata oldu: {error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Otomatik yükseltmeler etkinleştirildi" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Otomatik yükseltmeler etkisizleştirildi" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Dağıtım yükseltmesi etkinleştirildi" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Dağıtım yükseltmesi etkisizleştirildi" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Yükseltme işlemi başladı." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Yükseltmeyi başlatma başarısız oldu." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Sık yapılan özellik güncellemeleri etkinleştirildi." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Dağıtım yükseltmesi denemesi başlatılıyor." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7361,7 +7330,7 @@ msgstr "" "kullanıcıya, uygulamaya erişme yetkisi vermek için bir kullanıcı hesabının " "bir grubun parçası olmasını gerektirir." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7373,15 +7342,15 @@ msgstr "" "sadece admin grubunun kullanıcıları uygulamaları veya sistem " "ayarlarını değiştirebilir." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Kullanıcılar ve Gruplar" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Tüm hizmetlere ve sistem ayarlarına erişim" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP \"{search_item}\" girişini denetleme" @@ -7401,11 +7370,11 @@ msgstr "" "Zorunlu. 150 veya daha az karakter. Sadece İngilizce harfler, rakamlar ve " "@/./-/_ karakterleri." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Yetkilendirme Parolası" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7413,11 +7382,11 @@ msgstr "" "Hesap değişikliklerini yetkilendirmek için \"{user}\" kullanıcısının " "parolasını girin." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Geçersiz parola." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7431,12 +7400,12 @@ msgstr "" "kullanıcılar tüm hizmetlere oturum açabilecektir. Ayrıca SSH aracılığıyla " "sisteme oturum açabilir ve yönetici yetkilerine (sudo) sahip olabilirler." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "LDAP kullanıcısı oluşturma başarısız oldu: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "{group} grubuna yeni kullanıcı ekleme başarısız oldu: {error}" @@ -7456,41 +7425,41 @@ msgstr "" "tane olmak üzere birden çok anahtar girebilirsiniz. Boş satırlar ve # ile " "başlayan satırlar yoksayılacaktır." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "LDAP kullanıcısının yeniden adlandırılması başarısız oldu." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Kullanıcıyı gruptan kaldırma başarısız oldu." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Kullanıcıyı gruba ekleme başarısız oldu." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "SSH anahtarları ayarlanamıyor." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Kullanıcı durumunu değiştirme başarısız oldu." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "LDAP kullanıcı parolasının değiştirilmesi başarısız oldu." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Admin grubuna yeni kullanıcı ekleme başarısız oldu: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Konsol erişimini kısıtlama başarısız oldu: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Kullanıcı hesabı oluşturuldu, şu an oturum açtınız" @@ -7507,12 +7476,12 @@ msgstr "Parolayı Kaydet" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Kullanıcı Oluştur" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Kullanıcıyı Sil" @@ -7553,13 +7522,19 @@ msgid "The following administrator accounts exist in the system." msgstr "Sistemde aşağıdaki yönetici hesapları var." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, fuzzy, python-format +#| msgid "" +#| "Delete these accounts from command line and refresh the page to create an " +#| "account that is usable with %(box_name)s. On the command line run the " +#| "command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-" +#| "user {username}'. If an account is already usable with %(box_name)s, skip " +#| "this step." msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" "Bu hesapları komut satırından silin ve %(box_name)s ile kullanılabilen bir " "hesap oluşturmak için sayfayı yenileyin. Komut satırında 'echo " @@ -7568,7 +7543,7 @@ msgstr "" "bu adımı atlayın." #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Kullanıcılar" @@ -7601,34 +7576,34 @@ msgstr "" msgid "Save Changes" msgstr "Değişiklikleri Kaydet" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "%(username)s kullanıcısı oluşturuldu." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "%(username)s kullanıcısı güncellendi." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Kullanıcıyı Düzenle" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "{user} kullanıcısı silindi." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "LDAP kullanıcısının silinmesi başarısız oldu." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Parolayı Değiştir" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Parola başarılı olarak değiştirildi." @@ -7963,7 +7938,7 @@ msgstr "Sunucuya Bağlantıyı Sil" msgid "Server deleted." msgstr "Sunucu silindi." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7977,7 +7952,7 @@ msgstr "" "kullanılarak seçilebilir. Yönetim arayüzü ve üretilen web sayfaları mobil " "cihazlara uygundur." -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7991,7 +7966,7 @@ msgstr "" "Sayfalarınıza ve yazılarınıza daha iyi URL'ler sağlamak için yönetici " "arayüzünde kalıcı bağlantıları etkinleştirin." -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " @@ -8001,7 +7976,7 @@ msgstr "" "sırasında oluşturulur. Gelecekte yönetim arayüzüne erişmek için yönetici sayfası yerini işaretleyin." -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " @@ -8011,12 +7986,12 @@ msgstr "" "yükseltmesini el ile çalıştırmanız gerekir. Ek eklentiler veya temalar kendi " "sorumluluğunuzda yüklenebilir ve yükseltilebilir." -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Web Sitesi ve Blog" @@ -8033,7 +8008,7 @@ msgstr "" "WordPress sitesini veya blogunu görüntülemesine izin verir. Sadece ilk " "WordPress kurulumunu gerçekleştirdikten sonra etkinleştirin." -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8055,7 +8030,7 @@ msgstr "" "çekilmiş fotoğrafları bulmak kolaydır. Tek tek fotoğraflar, doğrudan bir " "bağlantı gönderilerek başkalarıyla paylaşılabilir." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8066,11 +8041,11 @@ msgstr "" "Ek kullanıcılar için hesaplar hem {box_name} cihazında hem de Zoph'da aynı " "kullanıcı adıyla oluşturulmak zorundadır." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Fotoğraf Düzenleyici" @@ -8123,96 +8098,92 @@ msgstr "Başlamak için bekleniyor: {name}" msgid "Finished: {name}" msgstr "Tamamlandı: {name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "{expression} paketi yükleme için mevcut değil" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "{package_name} paketi en son sürümdür ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "apt-get çalıştırılırken hata oldu" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "yükleniyor" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "indiriliyor" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "ortam değiştirme" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "yapılandırma dosyası: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "Paket yöneticisini beklerken zaman aşımı oldu" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Uygulama yükleniyor" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Uygulama güncelleniyor" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Uygulama yüklenirken hata oldu: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Uygulama güncellenirken hata oldu: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Uygulama yüklenirken hata oldu: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Uygulama güncellenirken hata oldu: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "Uygulama yüklendi." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Uygulama güncellendi" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Uygulama kaldırılıyor" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Uygulama kaldırılırken hata oldu: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Uygulama kaldırılırken hata oldu: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "Uygulama kaldırıldı." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Uygulama paketleri güncelleniyor" @@ -8272,53 +8243,54 @@ msgstr "Kurulum" msgid "Service %(service_name)s is not running." msgstr "%(service_name)s hizmeti çalışmıyor." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "%(box_name)s için temel işlevsellik ve web arayüzü" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Giriş" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Giriş" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Uygulamalar" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Uygulamalar" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Sistem" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Sistem" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Parolayı değiştir" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Kapat" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Oturumu kapat" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Dil seçin" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Oturum aç" @@ -8606,6 +8578,75 @@ msgstr "{app_id} kaldırılmadan önce" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "DNSSEC'i etkinleştir" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Etki Alanı Adı Sistemi Güvenlik Uzantılarını etkinleştir" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Güvenlik duvarı arka plan programı çalışmıyor. Lütfen çalıştırın. " +#~ "Güvenlik duvarı varsayılan olarak %(box_name)s ile etkinleştirilmiş " +#~ "gelir. Herhangi bir Debian tabanlı sistemde (%(box_name)s gibi), 'service " +#~ "firewalld start' komutunu kullanarak veya systemd 'systemctl start " +#~ "firewalld' olan bir sistem durumunda çalıştırabilirsiniz." + +#~ msgid "Migrate to ECC" +#~ msgstr "ECC'ye Geçir" + +#~ msgid "" +#~ "Your OpenVPN installation is currently using RSA. Switching to the modern " +#~ "Elliptic Curve Cryptography improves speed of establishing a connection " +#~ "and security. This operation is irreversible. It should only take a few " +#~ "minutes on most single board computers." +#~ msgstr "" +#~ "OpenVPN kurulumunuz şu anda RSA kullanıyor. Modern Eliptik Eğri " +#~ "Şifrelemesine geçiş, bağlantı kurma hızını ve güvenliği artırır. Bu işlem " +#~ "geri alınamaz. Çoğu tek kartlı bilgisayarda sadece birkaç dakika " +#~ "sürmektedir." + +#, python-format +#~ msgid "" +#~ "All new installations of OpenVPN on %(box_name)s will use ECC by default. " +#~ "We recommend migrating as soon as possible." +#~ msgstr "" +#~ "%(box_name)s cihazındaki tüm yeni OpenVPN kurulumları, varsayılan olarak " +#~ "ECC'yi kullanacaktır. Mümkün olan en kısa sürede geçiş yapmanızı öneririz." + +#, python-format +#~ msgid "" +#~ "Warning: Existing client profiles will be invalidated by this " +#~ "operation. All OpenVPN users on %(box_name)s must download their new " +#~ "profiles. OpenVPN clients compatible with ECC should be used to connect " +#~ "to this server." +#~ msgstr "" +#~ "Uyarı: Varolan istemci profilleri bu işlem tarafından geçersiz " +#~ "kılınacaktır. %(box_name)s cihazındaki tüm OpenVPN kullanıcıları yeni " +#~ "profillerini indirmek zorundadır. Bu sunucuya bağlanmak için ECC ile " +#~ "uyumlu OpenVPN istemcileri kullanılmalıdır." + +#~ msgid "Migrate" +#~ msgstr "Geçir" + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "Parola ile SSH kimlik doğrulaması etkisizleştirildi." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "Parola ile SSH kimlik doğrulaması etkinleştirildi." + +#~ msgid "Error running apt-get" +#~ msgstr "apt-get çalıştırılırken hata oldu" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "%(box_name)s için temel işlevsellik ve web arayüzü" + #~ msgid "Network Connections" #~ msgstr "Ağ Bağlantıları" diff --git a/plinth/locale/uk/LC_MESSAGES/django.po b/plinth/locale/uk/LC_MESSAGES/django.po index 5354268ba..a3bb66483 100644 --- a/plinth/locale/uk/LC_MESSAGES/django.po +++ b/plinth/locale/uk/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-10-09 07:43+0000\n" "Last-Translator: Tymofii Lytvynenko \n" "Language-Team: Ukrainian calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1042,23 +1035,23 @@ msgstr "" "до застосунку. Усі користувачі з доступом можуть користуватися всіма " "бібліотеками." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Використання бібліотеки ел. книжок calibre" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Бібліотека ел. книжок" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Назва нової бібліотеки" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" @@ -1066,7 +1059,7 @@ msgstr "" "Лише букви англійського алфавіту, цифри та знаки _ і - без пробілів чи " "спеціальних символів. Наприклад: My_Library_2000" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Бібліотека з такою назвою вже існує." @@ -1114,20 +1107,20 @@ msgstr "Перейти до бібліотеки %(library)s" msgid "Delete library %(library)s" msgstr "Видалити бібліотеку %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Бібліотеку створено." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Помилка виникла під час створення бібліотеки." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} видалено." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Не вдалося видалити {name}: {error}" @@ -1175,7 +1168,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Адміністрування сервера" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1183,18 +1176,18 @@ msgstr "" "Тут Ви можете задати деякі загальні параметри налаштувань, як-от назва " "компʼютера, назва домена, домашня сторінка вебсервера тощо." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Загальні налаштування" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Налаштування" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1310,47 +1303,47 @@ msgstr "" "Журнали містять інформацію про те, хто мав доступ до системи та інформацію " "про зневадження від різних сервісів" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Помилка параметру hostname: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Назву компʼютера задано" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Помилка встановлення доменної назви: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Доменну назву задано" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Помилка налаштування домашньої сторінки вебсервера: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Домашню сторінку вебсервера задано" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Помилка зміни розширеного режиму: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Відображення розширених застосунків і можливостей" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Приховування розширених застосунків і можливостей" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1362,7 +1355,7 @@ msgstr "" "комунікації можуть використовувати його для встановлення дзвінків між " "частинами, які по-іншому не можливо звʼязати між собою." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse або ejabberd потрібно налаштовувати з урахуванням деталей наведених тут." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "Помічник VoIP" @@ -1436,11 +1429,11 @@ msgstr "Помилка задавання часового поясу: {exceptio msgid "Time zone set" msgstr "Часовий пояс задано" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge – це клієнт BitTorrent із вебінтерфейсом." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1448,16 +1441,16 @@ msgstr "" "Типовий пароль – 'deluge', але Ви можете ввійти і змінити його відразу після " "ввімкнення цього сервісу." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Завантаження файлів через застосунки BitTorrent" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Вебклієнт BitTorrent" @@ -1584,7 +1577,7 @@ msgstr "Результат" msgid "Diagnostic Test" msgstr "Тест діагностики" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1595,7 +1588,7 @@ msgstr "" "кожних 24год.), то іншим може бути важко знайти Вас в Інтернеті. Це " "перешкоджатиме іншим пошук сервісів, що надаються цим {box_name}." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1613,7 +1606,7 @@ msgstr "" "новому IP, і якщо хтось з Інтернету запитає ваше DNS-ім'я, він отримає " "відповідь з вашою поточною IP-адресою." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1626,11 +1619,11 @@ msgstr "" "служби на основі URL-адреси оновлення за адресою freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Клієнт динамічної DNS" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Динамічна доменна назва" @@ -1762,7 +1755,7 @@ msgstr "Це поле обовʼязкове." #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1817,7 +1810,7 @@ msgstr "Сервер відмовив у зʼєднанні" msgid "Already up-to-date" msgstr "Вже оновлено" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1825,7 +1818,7 @@ msgstr "" "XMPP – це відкритий і стандартизований протокол спілкування. Тут Ви можете " "запустити і налаштувати свій XMPP-сервер ejabberd." -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web clientклієнт XMPP. Якщо ввімкнено, то отримати доступ до ejabberd " "зможе будь-який користувач із логіном {box_name}." -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn або налаштуйте зовнішній " "сервер." -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "Сервер чату" @@ -1975,7 +1968,7 @@ msgstr "" "виглядатиме як username@%(domainname)s. Ви можете налаштувати свій " "домен на системній сторінці Налаштувати." -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " @@ -1986,7 +1979,7 @@ msgstr "" "поштовим клієнтам отримувати доступ до вашої поштової скриньки за допомогою " "IMAP і POP3. Rspamd блокує спам." -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1999,7 +1992,7 @@ msgstr "" "обмеження після явного запиту. Дивіться сторінку посібника для отримання " "подробиць." -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -2012,10 +2005,10 @@ msgstr "" "user@mydomain.example. Вони також отримуватимуть пошту з усіх адрес, які " "мають вигляд user+foo@mydomain.example. Крім того, вони можуть додавати " "псевдоніми до своєї адреси електронної пошти. Необхідні псевдоніми, такі як " -"\"postmaster\", створюються автоматично, вказуючи на першого " -"користувача-адміністратора." +"\"postmaster\", створюються автоматично, вказуючи на першого користувача-" +"адміністратора." -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." @@ -2023,7 +2016,7 @@ msgstr "" "Застосунок Roundcube надає " "вебінтерфейс для доступу користувачів до ел. пошти." -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2153,7 +2146,7 @@ msgstr "Порт" msgid "Host/Target/Value" msgstr "Хост/ціль/значення" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2164,7 +2157,7 @@ msgstr "" "трафік Вашого {box_name}. Тримайте фаєрвол увімкненим і належно " "налаштованим, це зменшить ризик загроз безпеці з Інтернету." -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "Фаєрвол" @@ -2184,52 +2177,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "Порт {name} ({details}) недоступний для зовнішніх мереж" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"Демон фаєрвола не запущено. Будь ласка, запустіть його. Фаєрвол увімкнено " -"типово на %(box_name)s. У будь-якій системі на основі Debian (наприклад, " -"%(box_name)s) ви можете запустити його за допомогою команди 'service " -"firewalld start' або у випадку системи з systemd 'systemctl start firewalld'." - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "Сервіс/Порт" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "Дозволено" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "Вимкнено" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "Дозволяється" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "Дозволяється (лише внутрішні)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "Дозволяється (лише зовнішні)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "Блоковано" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2239,13 +2219,13 @@ msgstr "" "дозволений у фаєрволі і якщо Ви вимкнете сервіс, він також буде вимкнений у " "фаєрволі." -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "Розширені" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2298,7 +2278,7 @@ msgstr "Розпочати встановлення" msgid "Setup Complete" msgstr "Налаштування завершено" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2316,7 +2296,7 @@ msgstr "" "термінальний клієнт для Git або через різні доступні графічні клієнти. І Ви " "можете ділитися своїм кодом із людьми по всьому світу." -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." @@ -2324,68 +2304,68 @@ msgstr "" "Щоб дізнатися більше про те, як користуватися Git відвідайте навчання Git." -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "Доступ до читання-запису репозиторіїв Git" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "Gitweb" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "Просте розміщення Git" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "Некоректна URL-адреса репозиторію." -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "Некоректна назва репозиторію." -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" "Назва нового репозиторію або URL для імпортування зовнішнього репозиторію." -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "Опис репозиторію" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "Необовʼязково, для відображення на Gitweb." -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "Імʼя власника репозиторію" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "Приватний репозиторій" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "Дозволити доступ до цього репозиторію лише авторизованим користувачам." -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "Репозиторій із цією назвою вже існує." -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "Назва репозиторію" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "Рядок із букв і чисел, що унікально ідентифікує репозиторій." -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "Типова гілка" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "Gitweb відображає це як типову гілку." @@ -2429,19 +2409,19 @@ msgstr "Видалити Git-репозиторій %(name)s" msgid "Delete this repository permanently?" msgstr "Видалити цей репозиторій безповоротно?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "Репозиторій створено." -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "Помилка відбулася під час створення репозиторію." -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "Репозиторій змінено." -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "Змінити репозиторій" @@ -2594,8 +2574,8 @@ msgid "" "throughout the world. The FreedomBox Foundation would not exist without its " "supporters." msgstr "" -"Ви також можете допомогти проєкту фінансово, зробивши пожертву на рахунок неприбуткової " +"Ви також можете допомогти проєкту фінансово, зробивши пожертву на рахунок неприбуткової " "організації FreedomBox Foundation. Заснована у 2011 році, FreedomBox " "Foundation є неприбутковою організацією зі статусом 501(c)(3) зі штаб-" "квартирою у Нью-Йорку, яка існує для підтримки проєкту FreedomBox. Вона " @@ -2727,8 +2707,8 @@ msgid "" msgstr "" "Багато дописувачів та користувачів %(box_name)s також доступні в IRC-мережі " "irc.oftc.net. Приєднуйтесь та звертайтеся за допомогою на каналі #freedombox за допомогою вебінтерфейсу IRC." +"\"https://webchat.oftc.net/?randomnick=1&channels=freedombox&" +"prompt=1\">#freedombox за допомогою вебінтерфейсу IRC." #: plinth/modules/help/templates/help_manual.html:18 msgid "Download as PDF" @@ -2806,7 +2786,7 @@ msgstr "Про {box_name}" msgid "{box_name} Manual" msgstr "Посібник для {box_name}" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2818,7 +2798,7 @@ msgstr "" "надсилаючи зашифрований трафік через волонтерську мережу, розподілену по " "всьому світу." -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2826,26 +2806,26 @@ msgstr "" "Детальніше про I2P на їхній домашній сторінці проєкту." -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" "Перше відвідування наданого вебінтерфейсу розпочне процес налаштування." -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "Керування застосунком I2P" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "I2P" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "Мережа анонімності" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "Проксі I2P" @@ -2890,7 +2870,7 @@ msgstr "" "Завантажуйте файли, додаючи торенти або створюйте новий торент, щоб " "поділитися файлом." -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2900,7 +2880,7 @@ msgstr "" "легких мов розмітки, включаючи Markdown, та основні функції для роботи з " "блоґами, як-от коментарі та стрічки RSS." -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2914,15 +2894,15 @@ msgstr "" "\"{users_url}\">налаштуваннях користувача Ви можете змінити ці права або " "додавати нових користувачів." -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Вікі та блоґ" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "Перегляд і редагування застосунків вікі" @@ -2978,41 +2958,41 @@ msgstr "" "Ця дія видалить всі дописи, сторінки та коментарі, включаючи історію " "редагувань. Видалити цю вікі чи блог назавжди?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "Створено вікі {name}." -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "Не можливо створити вікі: {error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "Створено блоґ {name}." -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "Не можливо створити блоґ: {error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} видалено." -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "Не можливо видалити {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted — це сервер для Gobby, колективного редактора тексту." -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -3023,11 +3003,11 @@ msgstr "" "Gobby, стільничний клієнт і встановіть їх. Потім запустіть Gobby, " "виберіть «Зʼєднатися зі сервером» і введіть Вашу доменну назву {box_name}." -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "infinoted" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Сервер Gobby" @@ -3075,7 +3055,7 @@ msgstr "Відеокімната Janus" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "Інформація про ліцензію JavaScript" @@ -3095,7 +3075,7 @@ msgstr "JSXC" msgid "Chat Client" msgstr "Клієнт чату" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -3110,7 +3090,7 @@ msgstr "" "доступного домену. Для цього він підтверджує, що є власником домену в Let's " "Encrypt, центрі сертифікації (ЦС)." -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -3123,15 +3103,15 @@ msgstr "" "\"https://letsencrypt.org/repository/\">Угодою підписувача Let's Encrypt " "перед тим, як користуватися цією службою." -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "Сертифікати" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "Тестування не можливе: Нема налаштованих доменів." @@ -3196,7 +3176,7 @@ msgstr "" "Нема налаштованих доменів. Налаштуйте домени, " "щоб мати можливість отримати сертифікати для них." -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " @@ -3205,34 +3185,34 @@ msgstr "" "Сертифікат успішно відкликано для домена {domain}. Це може зайняти кілька " "хвилин, перш ніж почне діяти." -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "Не вдалося відкликати сертифікат для домену {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "Сертифікат успішно отримано для домену {domain}" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "Не вдалося отримати сертифікат для домену {domain}: {error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "Сертифікат успішно видалено для домену {domain}" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "Не вдалося видалити сертифікат для домену {domain}: {error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3249,7 +3229,7 @@ msgstr "" "можуть спілкуватися з користувачами на інших серверах Matrix через " "федеративність." -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " @@ -3259,7 +3239,7 @@ msgstr "" "Встановіть програму Coturn або налаштуйте " "зовнішній сервер." -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3358,7 +3338,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3370,7 +3350,7 @@ msgstr "" "вебсайту. Ви можете використовувати MediaWiki для розміщення вебсайту на " "зразок вікі, робити нотатки або співпрацювати з друзями над проєктами." -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3384,7 +3364,7 @@ msgstr "" "користувачів із самої MediaWiki перейшовши на сторінку Special:CreateAccount." -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." @@ -3392,12 +3372,12 @@ msgstr "" "Будь-хто, хто має посилання на цю вікі може читати її. Лише користувачі, що " "ввійшли можуть робити зміни вмісту." -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "MediaWiki" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "Вікі" @@ -3478,35 +3458,35 @@ msgstr "Пароль оновлено" msgid "Password update failed. Please choose a stronger password" msgstr "Не вдалося оновити пароль. Оберіть сильніший пароль" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "Публічні реєстрації дозволено" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "Публічні реєстрації вимкнено" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "Приватний режим дозволено" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "Приватний режим вимкнено" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "Типову шкурку змінено" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "Доменну назву оновлено" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "Назву сайту оновлено" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3519,11 +3499,11 @@ msgstr "" "портом (30000). Щоб підʼєднатися до сервера потрібено клієнт Minetest." -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "Minetest" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "Блокова пісочниця" @@ -3573,7 +3553,7 @@ msgstr "" msgid "Address" msgstr "Адреса" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3736,7 +3716,7 @@ msgstr "Захищена оболонка" msgid "Services" msgstr "Сервіси" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." @@ -3744,7 +3724,7 @@ msgstr "" "Налаштування мережевих пристроїв. Зʼєднання з Інтернетом через Ethernet, Wi-" "Fi або PPPoE. Ділитися цим зʼєднанням з іншими пристроями в мережі." -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." @@ -3752,7 +3732,7 @@ msgstr "" "Пристрої, що адмініструються іншими способами, можуть бути недоступними для " "налаштування тут." -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "Мережі" @@ -4148,7 +4128,7 @@ msgstr "Змінити зʼєднання" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "Зміни" @@ -4253,7 +4233,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "Метод" @@ -4269,7 +4249,7 @@ msgstr "Сервер DNS" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "Типово" @@ -4282,7 +4262,7 @@ msgid "This connection is not active." msgstr "Це зʼєднання неактивне." #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "Безпека" @@ -4847,7 +4827,7 @@ msgstr "Зʼєднання {name} видалено." msgid "Failed to delete connection: Connection not found." msgstr "Не вдалося видалити зʼєднання: Зʼєднання не знайдено." -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4858,20 +4838,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "Підʼєднання до сервісів VPN" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "Віртуальна приватна мережа" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4882,61 +4862,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "Профіль" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "Завантажити мій профіль" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4945,19 +4893,19 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" "{box_name} підʼєднано до (бездротового) маршрутизатора, яким Ви не можете " "керувати." -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." @@ -4965,7 +4913,7 @@ msgstr "" "Ваш постачальник Інтернет-послуг не надає Вам зовнішньої IP-адреси, а надає " "Інтернет-зʼєднання через NAT." -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." @@ -4973,11 +4921,11 @@ msgstr "" "Ваш постачальник Інтернет-послуг не надає Вам статичної IP-адреси і Ваша IP-" "адреса змінюється кожного разу, коли Ви підʼєднуєтеся до Інтернету." -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "Ваш ISP обмежує вхідні зʼєднання." -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4986,23 +4934,23 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "Публічна видимість" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "Домен PageKite" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "Домен сервера" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -5010,65 +4958,65 @@ msgstr "" "Виберіть Ваш сервер для pagekite. Вкажіть \"pagekite.net\", щоб " "використовувати типовий сервер pagekite.net." -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "Порт сервера" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "Порт Вашого сервера pagekite (типово: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Назва kite" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "Приклад: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "Неправильна назва kite" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "протокол" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "зовнішній порт (frontend)" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "внутрішній порт (feedombox)" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "Дозволити піддомени" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "Видалено власний сервіс" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "Цей сервіс уже доступний як стандартний сервіс." -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "Додано власний сервіс" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "Цей сервіс вже існує" @@ -5102,29 +5050,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Вебсервер (HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "Сайт буде доступний за адресою http://{0}" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Вебсервер (HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "Сайт доступний за адресою https://{0}" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "Захищена оболонка (SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -5168,8 +5116,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "Перезапустити" @@ -5215,6 +5163,39 @@ msgstr "" msgid "Shut Down Now" msgstr "Вимкнути зараз" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -5246,7 +5227,7 @@ msgstr "Веб-проксі" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -5263,7 +5244,7 @@ msgstr "" "один чи більше клієнтів Quassel для приєднання чи відʼєднання з настільного " "ПК чи мобільного." -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your настільного ПК " "і мобільного." -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "Quassel" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "Клієнт IRC" @@ -5286,7 +5267,7 @@ msgstr "Клієнт IRC" msgid "Quasseldroid" msgstr "Quasseldroid" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -5301,19 +5282,19 @@ msgstr "" "\">підтримувані клієнтські застосунки. До Radicale може мати доступ будь-" "який користувач з імʼям входу для {box_name}." -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "Radicale" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "Календар і адресна книга" @@ -5377,7 +5358,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "Оновлено налаштування прав доступу" @@ -5421,8 +5402,8 @@ msgstr "" "облікового запису Google і сервером – imaps://imap.gmail.com. " "Зауважте, що потрібно дозволити «Малозахищені додатки» в налаштуваннях " "облікового запису Google (https://www.google.com/settings/security/" -"lesssecureapps)." +"lesssecureapps\">https://www.google.com/settings/security/lesssecureapps)." #: plinth/modules/roundcube/__init__.py:50 msgid "Email Client" @@ -5468,7 +5449,7 @@ msgstr "" "RSS для відстеження різних вебсайтів. Під час додавання стрічки " "дозвольте автентифікацію і використовуйте свої облікові дані {box_name}." -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "Читати і підписатися на стрічки новин" @@ -5481,13 +5462,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "Ґенератор стрічок RSS" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5496,31 +5477,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "Доступ до приватних поширень" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "Samba" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "Мережеве сховище файлів" @@ -5598,15 +5579,15 @@ msgstr "" msgid "Action" msgstr "Дія" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "Диск ОС FreedomBox" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5632,7 +5613,7 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "Помилка вимкнення поширення: {error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." @@ -5640,7 +5621,7 @@ msgstr "" "Searx — це система збірного пошуку в Інтернеті, яка поважає приватність. " "Вона збирає і відображає результати з різних пошукових систем." -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." @@ -5648,40 +5629,40 @@ msgstr "" "Searx може використовуватися для обходу стеження та профілювання пошуковими " "системами." -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "Пошук в Інтернеті" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "Searx" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Вебпошук" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "Безпечний пошук" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" "Вибрати типовий сімейний фільтр для застосування до Ваших результатів пошуку." -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "Модерований" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "Строгий" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "Дозволити публічний доступ" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" "Дозволити користуватися цим застосуноком кожному, хто має до нього доступ." @@ -5843,14 +5824,14 @@ msgstr "Закладки" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5859,48 +5840,48 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "Проксі Socks5" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "Рекомендоване" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "Сервер" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "Назва хоста сервера або IP-адреса" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "Номер порта сервера" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" "Пароль, що використовується для шифрування даних. Має відповідати паролю " "сервера." -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "Метод шифрування. Має відповідати налаштуванням на сервері." -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " @@ -5909,15 +5890,15 @@ msgstr "" "Обмін дозволяє Вам обмінюватися файлами і теками з Вашого {box_name}, через " "Інтернет, до обраної групи користувачів." -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "Обмін" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "Назва ділянки" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." @@ -5925,37 +5906,37 @@ msgstr "" "Рядок з малих літер та цифр, що унікально позначає ділянку. Приклад: " "media." -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "Шлях до ділянки" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "Шлях до теки на сервері, якою Ви маєте намір ділитися." -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "Публічна ділянка" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "Зробіть файли в теці доступними для будь-кого за посиланням." -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "Групи користувачів, які можуть зчитувати файли з ділянки:" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "Користувачі вибраних груп зможуть читати файли цієї ділянки." -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "Ділянка з такою назвою вже існує." -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "Ділянка має бути спільною або публічною для щонайменше однієї групи" @@ -5992,19 +5973,19 @@ msgstr "Ділянку додано." msgid "Add Share" msgstr "Додати ділянку" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "Ділянку змінено." -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "Змінити ділянку" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "Ділянку видалено." -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -6014,7 +5995,7 @@ msgstr "" "можна використовувати для відкочування системи до попереднього хорошого " "стану в разі небажаних змін системи." -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -6025,7 +6006,7 @@ msgstr "" "встановлення ПЗ. Старі зрізи автоматично видалятимуться відповідно до " "налаштувань нижче." -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for резервних копій, поки вони " "не зберігаються на одному розділі. " -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "Зрізи сховища" @@ -6138,7 +6119,7 @@ msgstr "Дата" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "Видалити зріз" @@ -6186,57 +6167,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "створено вручну" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "за часом" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "apt" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "Керування зрізами" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "Створено зріз." -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "Налаштування зрізів сховища оновлено" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "Помилка дії: {0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "Видалити вибрані зрізи" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "Зріз зараз використовується. Повторіть пізніше." -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "Відкочено до зрізу #{number}." -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "Систему потрібно перезапустити, щоб завершити відкат." -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -6248,7 +6229,7 @@ msgstr "" "виконувати завдання з адміністрування, копіювання файлів або запускати інші " "сервіси через певні зʼєднання." -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "Сервер захищеної оболонки (SSH)" @@ -6286,14 +6267,6 @@ msgstr "Алґоритм" msgid "Fingerprint" msgstr "Відбиток" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "автентифікація SSH із вимкненим паролем." - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "автентифікація SSH із дозволеним паролем." - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -6306,7 +6279,7 @@ msgstr "Вхід" msgid "Logged out successfully." msgstr "Вийшли успішно." -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -6317,145 +6290,145 @@ msgstr "" "{box_name}. Під час використання сховище даних можна переглядати, монтувати " "і відмонтовувати знімні накопичувачі, розширювати розділ root тощо." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "Сховище" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} байтів" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} КБ" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} МБ" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} ГБ" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} ТБ" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "Операція невдала." -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "Операцію скасовано." -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Пристрій вже відмонтований." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "Час операції вийшов." -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "Операція вже була скасована." -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Пристрій уже змонтовано." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Пристрій не змонтовано." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Пристрій змонтовано іншим користувачем." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" "Мало простору в розділі системи: {percent_used}% використано, {free_space} " "вільно." -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "Мало простору на диску" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "Некоректна назва каталогу." -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "Каталог не існує." -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "Шлях не є каталогом." -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "Каталог не може читатися користувачем." -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "Каталог не може записуватися користувачем." -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "Каталог" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "Підкаталог (необовʼязково)" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "Інший каталог (вкажіть нижче)" @@ -6489,7 +6462,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "Розширити кореневий розділ" @@ -6509,30 +6482,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "Помилка розширення розділу: {exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "Розділ успішно розширено." -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "{drive_vendor} {drive_model} можна безпечно відʼєднувати." -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "Пристрій можна безпечно витягати." -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "Помилка виймання пристрою: {error_message}" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6540,7 +6513,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6552,20 +6525,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "Адміністрування програми Syncthing" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "Syncthing" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "Синхронізація файлів" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6578,7 +6551,7 @@ msgstr "" "під час вебсерфінгу, проєкт Tor радить використовувати Tor Browser." -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " @@ -6586,40 +6559,40 @@ msgid "" msgstr "" "Порт SOCKS для Tor на Вашому {box_name} для внутрішніх мереж – TCP 9050." -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "Tor" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Сервіс Tor Onion" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6717,11 +6690,11 @@ msgstr "Сервіс Onion" msgid "Ports" msgstr "Порти" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "Оновлення налаштувань" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "Помилка налаштування застосунку: {error}" @@ -6779,7 +6752,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -6789,7 +6762,7 @@ msgstr "" "спроєктований читати новини з будь-яких місць, при цьому намагається бути " "максимально близьким до стільничної програми, на скільки це можливо." -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -6798,7 +6771,7 @@ msgstr "" "Якщо дозволено, Tiny Tiny RSS може бути доступним для будь-якого користувача, що належить до групи feed-reader." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." @@ -6806,11 +6779,11 @@ msgstr "" "Коли використовуєте мобільний або стільничний застосунок для Tiny Tiny RSS, " "використовуйте URL /tt-rss-app для зʼєднання." -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "Tiny Tiny RSS" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "Читання новинних стрічок" @@ -6818,12 +6791,12 @@ msgstr "Читання новинних стрічок" msgid "Tiny Tiny RSS (Fork)" msgstr "Tiny Tiny RSS (відгілка)" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "Перевірити і застосувати останні оновлення безпеки і ПЗ." -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6831,33 +6804,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "Оновлення ПЗ" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox оновлено" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "Не можливо запустити оновлення дистрибутиву" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "Оновлення дистрибутиву розпочато" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -7026,44 +6999,44 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "Тестувати оновлення дистрибутиву зараз" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "Дозволено автоматичні оновлення" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "Вимкнено автоматичні оновлення" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "Дозволено оновлення дистрибутиву" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "Вимкнено оновлення дистрибутиву" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "Процес оновлення розпочато." -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "Не вдалося розпочати оновлення." -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "Оновлення частих можливостей активовано." -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "Запуск тесту оновлення дистрибутиву." -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7074,7 +7047,7 @@ msgstr "" "застосунки також вимагають, щоб обліковий запис був частиною групи, щоб " "отримати авторизований доступ до застосунку." -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7086,15 +7059,15 @@ msgstr "" "користувачі з групи admin можуть змінювати застосунки або системні " "налаштування." -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "Користувачі і групи" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "Доступ до всіх сервісів і налаштувань системи" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Перевірка запису LDAP \"{search_item}\"" @@ -7113,11 +7086,11 @@ msgid "" msgstr "" "Обовʼязково. 150 знаків, не більше. Лише англійські букви, цифри і @/./-/_." -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "Пароль для авторизації" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." @@ -7125,11 +7098,11 @@ msgstr "" "Уведіть пароль для користувача \"{user}\", щоб авторизувати зміни облікового " "запису." -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "Неправильний пароль." -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -7143,12 +7116,12 @@ msgstr "" "входити в усі сервіси. Вони також можуть входити в систему через SSH і мати " "адміністративні права (sudo)." -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Не вдалося створити користувача LDAP: {error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Не вдалося додати нового користувача до групи {group}: {error}" @@ -7167,41 +7140,41 @@ msgstr "" "систему без використання пароля. Ви можете вказати декілька ключів, один на " "кожен рядок. Порожні рядки і рядки, що починаються на # іґноруються." -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "Не вдалося перейменувати користувача LDAP." -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "Не вдалося вилучити користувача з групи." -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "Не вдалося додати користувача до групи." -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "Не можливо задати ключі SSH." -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "Не вдалося змінити стан користувача." -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "Не вдалося змінити пароль користувача LDAP." -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Не вдалося додати нового користувача до адмінської групи: {error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "Не вдалося обмежити доступ до консолі: {error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "Обліковий запис користувача створено, Ви ввійшли в систему" @@ -7218,12 +7191,12 @@ msgstr "Зберегти пароль" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "Створити користувача" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "Видалити користувача" @@ -7264,17 +7237,17 @@ msgid "The following administrator accounts exist in the system." msgstr "Наступні облікові записи адміністратора існують у системі." #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "Користувачі" @@ -7307,34 +7280,34 @@ msgstr "" msgid "Save Changes" msgstr "Зберегти зміни" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "Створено користувача %(username)s." -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "Користувача %(username)s оновлено." -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "Зміни користувача" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "Користувача {user} видалено." -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "Не вдалося видалити користувача LDAP." -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "Зберегти пароль" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "Пароль змінено успішно." @@ -7650,7 +7623,7 @@ msgstr "Видалити зʼєднання до сервера" msgid "Server deleted." msgstr "Сервер видалено." -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7659,7 +7632,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7668,26 +7641,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "Вебсайт і блоґ" @@ -7701,7 +7674,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7723,7 +7696,7 @@ msgstr "" "календарного перегляду. Окремими світлинами можна ділитися з іншими, " "надіславши пряме посилання." -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7734,11 +7707,11 @@ msgstr "" "Для додаткових користувачів потрібно створити облікові записи і в " "{box_name}, і в Zoph з тим же іменем користувача." -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "Упорядник світлин" @@ -7789,96 +7762,92 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Пакунок {package_name} має останню версію ({latest_version})" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "Помилка запуску apt-get" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "встановлення" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "завантаження" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "зміна медія" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "файл конфіґурації: {file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "Встановлення застосунку" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "Оновлення застосунку" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Помилка встановлення застосунку: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Помилка оновлення застосунку: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "Помилка встановлення застосунку: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "Помилка оновлення застосунку: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "Застосунок встановлено." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "Застосунок оновлено" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "Видалення застосунку" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Помилка видалення застосунку: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Помилка видалення застосунку: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "Застосунок видалено." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "Оновлення пакунків застосунків" @@ -7937,53 +7906,54 @@ msgstr "Встановлення" msgid "Service %(service_name)s is not running." msgstr "Сервіс %(service_name)s не запущено." -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "Функціональність ядра та вебінтерфейс для %(box_name)s" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " Домівка" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "Домівка" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " Застосунки" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "Застосунки" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " Система" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "Система" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "Змінити пароль" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "Вимкнути" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "Вийти" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "Вибрати мову" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "Увійти" @@ -8270,6 +8240,38 @@ msgstr "перед видаленням {app_id}" msgid "Gujarati" msgstr "Gujarati" +#~ msgid "Enable DNSSEC" +#~ msgstr "Увімкнути DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Дозволити розширення безпеки системи доменних назв" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "Демон фаєрвола не запущено. Будь ласка, запустіть його. Фаєрвол увімкнено " +#~ "типово на %(box_name)s. У будь-якій системі на основі Debian (наприклад, " +#~ "%(box_name)s) ви можете запустити його за допомогою команди 'service " +#~ "firewalld start' або у випадку системи з systemd 'systemctl start " +#~ "firewalld'." + +#~ msgid "SSH authentication with password disabled." +#~ msgstr "автентифікація SSH із вимкненим паролем." + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "автентифікація SSH із дозволеним паролем." + +#~ msgid "Error running apt-get" +#~ msgstr "Помилка запуску apt-get" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "Функціональність ядра та вебінтерфейс для %(box_name)s" + #~ msgid "Network Connections" #~ msgstr "Мережеві зʼєднання" diff --git a/plinth/locale/vi/LC_MESSAGES/django.po b/plinth/locale/vi/LC_MESSAGES/django.po index b299b8a36..349c16aa5 100644 --- a/plinth/locale/vi/LC_MESSAGES/django.po +++ b/plinth/locale/vi/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-07-28 08:34+0000\n" "Last-Translator: bruh \n" "Language-Team: Vietnamese calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1055,29 +1048,29 @@ msgstr "" "ứng dụng. Tất cả người dùng có quyền truy cập đều có thể sử dụng tất cả các " "thư viện." -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "Sử dụng thư viện sách điện tử của calibre" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "Thư viện sách điện tử" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "Tên của thư viện mới" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "Một thư viện có tên này đã tồn tại." @@ -1125,20 +1118,20 @@ msgstr "Đi đến thư viện %(library)s" msgid "Delete library %(library)s" msgstr "Xoá thư viện %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "Đã tạo thư viện." -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "Đã xảy ra lỗi trong khi tạo thư viện." -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "Đã xoá {name}." -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "Không thể xoá {name}: {error}" @@ -1186,7 +1179,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "Quản trị máy chủ" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1194,18 +1187,18 @@ msgstr "" "Ở đây bạn có thể đặt một số tùy chọn thiết lập chung như tên máy chủ, tên " "miền, trang chủ của máy chủ web, v.v." -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "Thiết lập chung" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "Thiết lập" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1317,47 +1310,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "Lỗi khi đặt tên máy chủ: {exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "Đã đặt tên máy chủ" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "Lỗi khi đặt tên miền: {exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "Đã đặt tên miền" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "Lỗi khi đặt trang chủ của máy chủ web: {exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "Đã đặt trang chủ của máy chủ web" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "Lỗi khi thay đổi chế độ nâng cao: {exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "Đang hiện các ứng dụng và tính năng nâng cao" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "Đang ẩn các ứng dụng và tính năng nâng cao" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1369,7 +1362,7 @@ msgstr "" "các máy chủ giao tiếp khác có thể sử dụng nó để thiết lập một cuộc gọi giữa " "các bên mà không thể kết nối với nhau nếu không có nó." -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as ejabberd cần phải được thiết lập với các chi tiết được cung " "cấp ở đây." -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "Trợ giúp cho VoIP" @@ -1442,11 +1435,11 @@ msgstr "Lỗi khi đặt múi giờ: {exception}" msgid "Time zone set" msgstr "Đã đặt múi giờ" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge là một ứng dụng khách cho BitTorrent, nó có một Giao diện Web." -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." @@ -1454,16 +1447,16 @@ msgstr "" "Mật khẩu mặc định là 'deluge', nhưng bạn nên đăng nhập và đổi nó ngay lập " "tức sau khi bật dịch vụ này." -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "Tải các tệp xuống bằng các ứng dụng BitTorrent" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "Ứng dụng khách trên web cho BitTorrent" @@ -1589,7 +1582,7 @@ msgstr "Kết quả" msgid "Diagnostic Test" msgstr "Kiểm tra chẩn đoán" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1600,7 +1593,7 @@ msgstr "" "24h), những người khác có thể khó tìm bạn trên Internet. Việc này sẽ ngăn " "những người khác tìm các dịch vụ được {box_name} này cung cấp." -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1617,7 +1610,7 @@ msgstr "" "phân tên DNS của bạn cho IP mới, và nếu ai đó từ Internet hỏi tên DNS của " "bạn, họ sẽ nhận một phản hồi với địa chỉ IP hiện tại của bạn." -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 #, fuzzy #| msgid "" #| "If you are looking for a free dynamic DNS account, you may find a free " @@ -1637,11 +1630,11 @@ msgstr "" "phí dựa trên URL cập nhật tại freedns.afraid.org." -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "Ứng dụng khách DNS động" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "Tên miền động" @@ -1775,7 +1768,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1840,13 +1833,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1970,14 +1963,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1985,7 +1978,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1995,13 +1988,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2142,7 +2135,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2150,7 +2143,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -2170,61 +2163,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2270,7 +2254,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2281,73 +2265,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2391,19 +2375,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2696,7 +2680,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2704,31 +2688,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2765,14 +2749,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2781,15 +2765,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2843,41 +2827,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2885,11 +2869,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2935,7 +2919,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2953,7 +2937,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2963,7 +2947,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2971,15 +2955,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -3042,41 +3026,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3086,14 +3070,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -3174,7 +3158,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3182,7 +3166,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3191,18 +3175,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3273,39 +3257,39 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "Đã đặt tên miền" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "Đã đặt tên miền" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3314,11 +3298,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3363,7 +3347,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3524,19 +3508,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3882,7 +3866,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3987,7 +3971,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -4003,7 +3987,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -4016,7 +4000,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4552,7 +4536,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4563,20 +4547,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4586,61 +4570,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4649,33 +4601,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4684,87 +4636,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4798,29 +4750,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4862,8 +4814,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4905,6 +4857,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4936,7 +4919,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4947,7 +4930,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4967,7 +4950,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4977,19 +4960,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -5048,7 +5031,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -5120,7 +5103,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5133,13 +5116,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5148,31 +5131,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5250,15 +5233,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5284,51 +5267,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5481,14 +5464,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5497,97 +5480,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5624,26 +5607,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5651,14 +5634,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5752,7 +5735,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5800,57 +5783,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5858,7 +5841,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5891,14 +5874,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5911,7 +5886,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5922,143 +5897,143 @@ msgstr "" "của bạn. Bạn có thể xem phương tiện lưu trữ hiện đang sử dụng, gắn và bỏ gắn " "phương tiện có thể rút ra, mở rộng phân vùng root, v.v." -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "Thiết bị này đã đang bỏ gắn rồi." -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "Đang thử bỏ gắn một thiết bị đang bận." -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "Thiết bị này đã được gắn rồi." -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "Thiết bị này chưa được gắn." -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "Thiết bị này được một người dùng khác gắn." -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6092,7 +6067,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -6110,30 +6085,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6141,7 +6116,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6153,20 +6128,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6175,47 +6150,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6313,13 +6288,13 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "Đã xảy ra lỗi trong khi thiết lập." -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6377,14 +6352,14 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "It can be accessed by any user on {box_name} " @@ -6396,17 +6371,17 @@ msgstr "" "Nó có thể được truy cập bởi bất kỳ người dùng nào trên {box_name} thuộc về nhóm admin." -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6414,12 +6389,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6427,33 +6402,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6601,51 +6576,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6653,15 +6628,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6679,21 +6654,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6702,12 +6677,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6723,41 +6698,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6774,12 +6749,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6817,17 +6792,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6858,34 +6833,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7194,7 +7169,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7203,7 +7178,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7212,26 +7187,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7245,7 +7220,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7258,7 +7233,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7266,11 +7241,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7320,110 +7295,104 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "Lỗi trong khi sao lưu" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Lỗi khi cài đặt ứng dụng: {string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Lỗi khi cài đặt ứng dụng: {string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Ứng dụng đã được cài đặt." -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Lỗi khi cài đặt ứng dụng: {string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Ứng dụng đã được cài đặt." -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7474,53 +7443,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -7785,6 +7755,17 @@ msgstr "" msgid "Gujarati" msgstr "" +#~ msgid "Enable DNSSEC" +#~ msgstr "Bật DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "Bật Phần mở rộng bảo mật cho Hệ thống tên miền" + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "Lỗi trong khi sao lưu" + #~ msgid "" #~ "Cockpit requires that you access it through a domain name. It will not " #~ "work when accessed using an IP address as part of the URL." diff --git a/plinth/locale/zh_Hans/LC_MESSAGES/django.po b/plinth/locale/zh_Hans/LC_MESSAGES/django.po index 413acf63c..e1fa24f81 100644 --- a/plinth/locale/zh_Hans/LC_MESSAGES/django.po +++ b/plinth/locale/zh_Hans/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Plinth\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2022-09-03 14:18+0000\n" "Last-Translator: Eric \n" "Language-Team: Chinese (Simplified) calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -998,29 +991,29 @@ msgstr "" "只有属于calibre组的用户才能够访问该应用程序。所有有权限的用户都可以" "使用所有的图书馆。" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "使用 calibre 电子书库" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "电子书库" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "新库名称" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "已存在同名的库。" @@ -1066,20 +1059,20 @@ msgstr "转到库%(library)s" msgid "Delete library %(library)s" msgstr "删除站点 %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "创建了库。" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "在创建库时发生了一个错误。" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} 已删除。" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "不能删除 {name}:{error}" @@ -1123,24 +1116,24 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "服务器管理" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." msgstr "在这里你可以设置一些一般的配置选项,如主机名、域名、网络服务器主页等。" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "常规配置" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "配置" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1247,47 +1240,47 @@ msgid "" "from various services" msgstr "日志记录了访问系统的人员,以及各种服务的调试信息" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "设置主机名错误:{exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "主机名设置" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "设置域名错误:{exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "域名集" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "设置主机名错误:{exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "网页服务器主页已设置" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "更改为高级模式时错误:{exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "展现先进的应用和特征" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "隐藏先进的应用和特征" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1297,7 +1290,7 @@ msgstr "" "Coturn是一个服务器,通过提供TURN和STUN协议的实现来促进音频/视频通话和会议。" "WebRTC、SIP和其他通信服务器可以使用它在无法相互连接的各方之间建立通话。" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse或" "ejabberd等服务器需要用这里提供的细节进行配置。" -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "网络电话助手" @@ -1364,26 +1357,26 @@ msgstr "设置时区错误:{exception}" msgid "Time zone set" msgstr "时区设置" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge 是一个有网页界面的 BitTorrent 客户端。" -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." msgstr "默认密码是“deluge”,但是你需要在启用此服务以后立刻登录并修改它。" -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "使用BitTorrent应用程序下载文件" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "启用 Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent 网页客户端" @@ -1508,7 +1501,7 @@ msgstr "结果" msgid "Diagnostic Test" msgstr "诊断测试" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1518,7 +1511,7 @@ msgstr "" "如果您的互联网提供商定期(例如每24小时)更改您的IP地址,其他人可能很难在互联" "网上找到您。这会阻止其他人找到由此 {box_name} 提供的服务。" -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1534,7 +1527,7 @@ msgstr "" "器会将您的 DNS 名称分配给新的 IP,如果互联网上的某人要求您的 DNS 名称,他们将" "从您当前 IP 地址收到响应。" -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1546,11 +1539,11 @@ msgstr "" "服务,或您可以在freedns.afraid.org 找到免费更新网址服务。" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "动态 DNS 客户端" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "动态域名" @@ -1671,7 +1664,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1726,7 +1719,7 @@ msgstr "服务器拒绝连接" msgid "Already up-to-date" msgstr "已是最新" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." @@ -1734,7 +1727,7 @@ msgstr "" "XMPP 是一种开放标准的通信协议。在这里你可以运行并配置您的 XMPP 服务器,称为 " "ejabberd。" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client。启用后,任何有 {box_name} 登录的用户均可访" "问 ejabberd。" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn应用程序或配置一个外部服务器。" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "ejabberd" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "聊天服务器" @@ -1870,14 +1863,14 @@ msgstr "" "%(domainname)s。你可以在系统的配置中设置你" "的域名。" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1885,7 +1878,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1895,13 +1888,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2026,7 +2019,7 @@ msgstr "端口" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2036,7 +2029,7 @@ msgstr "" "防火墙控制你的 {box_name} 上的进出网络流量。启用并正确配置防火墙上可以减少来" "自互联网的安全威胁。" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "防火墙" @@ -2056,52 +2049,39 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" -"防火墙守护程序未运行。请运行它。防火墙默认在 %(box_name)s 上启用。在任何基于 " -"Debian 的系统(例如 %(box_name)s)上,要运行它,您可以使用命令 “service " -"firewalld start” ,在使用 systemd 的系统上则使用 “systemctl start " -"firewalld”命令。" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "服务/端口" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "启用" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "已禁用" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "允许" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "允许(只允许内部连接)" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "允许(只允许外部连接)" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "已阻止" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " @@ -2110,13 +2090,13 @@ msgstr "" "防火墙的操作是自动的。当您启用服务时它也在防火墙中允许,当禁用一项服务时也会" "禁用防火墙中的相应服务。" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2162,7 +2142,7 @@ msgstr "启动安装程序" msgid "Setup Complete" msgstr "安装完成" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2173,73 +2153,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "无效的存储库 URL。" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "无效的存储库名称。" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "新存储库的名称或用于导入现有存储库的 URL。" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "存储库描述" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "储存库所有者名称" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "私有存储库" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "已存在同名存储库。" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "存储库名称" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "默认分支" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2283,19 +2263,19 @@ msgstr "删除 Git 存储库 %(name)s " msgid "Delete this repository permanently?" msgstr "永久删除此存储库?" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "已创建储存库。" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "创建存储库时发生错误。" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "已编辑储存库。" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "编辑存储库" @@ -2614,7 +2594,7 @@ msgstr "关于 {box_name}" msgid "{box_name} Manual" msgstr "{box_name} 手册" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2622,7 +2602,7 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." @@ -2630,25 +2610,25 @@ msgstr "" "I2P 项目的更多信息,请参阅 " "主页。" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "管理 I2P 应用程序" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "匿名网络" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "I2P 代理" @@ -2685,7 +2665,7 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " @@ -2694,7 +2674,7 @@ msgstr "" "ikiwiki是一个简单的 wiki 和博客应用程序。它支持几种轻量级标记语言,包括 " "Markdown 和常见的博客功能,如评论和 RSS 源。" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2703,15 +2683,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "ikiwiki" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "Wiki 和博客" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "查看和编辑 wiki 应用程序" @@ -2766,41 +2746,41 @@ msgid "" msgstr "" "此操作将删除所有文章、 网页和评论包括修订历史记录。 永久删除此 wiki 或博客吗?" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "创建 wiki {name}。" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "不能创建 wiki:{error}" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "已创建的博客 {name}。" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "不能创建博客:{error}" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "{title} 已被删除。" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "无法删除 {title}: {error}" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "infinoted 是一个 Gobby 服务器,Gobby 是一个协作化的文本编辑器。" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2810,11 +2790,11 @@ msgstr "" "要使用它, 下载 Gobby 的桌面客户端并" "安装。然后启动 Gobby 并选择“连接到服务器”并书入你的 {box_name} 域名即可。" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "Gobby 服务器" @@ -2860,7 +2840,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2878,7 +2858,7 @@ msgstr "" msgid "Chat Client" msgstr "聊天客户端" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2891,7 +2871,7 @@ msgstr "" "动获取和设置每个可用域名的数字证书。它通过向 Let's Encrypt 证明自己是一个域名" "的所有者。Let's Encrypt 是一个证书颁发机构(CA)。" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2902,15 +2882,15 @@ msgstr "" "(ISRG)为公众利益而设立。请在使用此服务之前阅读并同意 Let's Encypt 订阅者协议。" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "Let's Encrypt" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "证书" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2975,41 +2955,41 @@ msgstr "" "还没有配置域名。配置域名可以为它们获得相应的证" "书。" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "成功吊销了域名 {domain} 的证书。可能需要一会儿才能生效。" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "无法为 {domain} 撤销证书:{error}" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "为域名 {domain} 成功获得证书" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "未能为域名 {domain} 获取证书:{error}" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "成功删除域名 {domain} 的证书" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "删除 {domain} 域名证书失败:{error}" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -3019,14 +2999,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "Matrix Synapse" @@ -3109,7 +3089,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3117,7 +3097,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3126,18 +3106,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "共笔文档" @@ -3206,35 +3186,35 @@ msgstr "密码已更新" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "公开注册已启用" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "已禁用公开注册" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "已启用私密模式" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "已禁用私密模式" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "默认皮肤已更改" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 msgid "Domain name updated" msgstr "域名已更新" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 msgid "Site name updated" msgstr "站点名已更新" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3246,11 +3226,11 @@ msgstr "" "(30000)上运行 Minetest 服务器。要连接到服务器,需要 Minetest 客户端。" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "方块沙盒" @@ -3295,7 +3275,7 @@ msgstr "禁用后,玩家不能死或受到任何伤害。" msgid "Address" msgstr "地址" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3456,19 +3436,19 @@ msgstr "安全 Shell" msgid "Services" msgstr "服务" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "网络" @@ -3824,7 +3804,7 @@ msgstr "编辑连接" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "編輯" @@ -3929,7 +3909,7 @@ msgstr "IPv4" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "方法" @@ -3945,7 +3925,7 @@ msgstr "DNS 服务器" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "默认" @@ -3958,7 +3938,7 @@ msgid "This connection is not active." msgstr "此连接未处于激活状态。" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "安全" @@ -4498,7 +4478,7 @@ msgstr "连接 {name} 已删除。" msgid "Failed to delete connection: Connection not found." msgstr "删除连接失败: 找不到连接。" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4513,20 +4493,20 @@ msgstr "" "供的私人/内部服务。您还可以通过 {box_name} 访问互联网的其他部分,以增加安全性" "和匿名性。" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "连接到 VPN 服务" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "OpenVPN" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "虚拟专用网络" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4536,64 +4516,38 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "迁移" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "配置文件" -#: plinth/modules/openvpn/templates/openvpn.html:25 -#, python-format +#: plinth/modules/openvpn/templates/openvpn.html:15 +#, fuzzy, python-format +#| msgid "" +#| "To connect to %(box_name)s's VPN, you need to download a profile and feed " +#| "it to an OpenVPN client on your mobile or desktop machine. OpenVPN " +#| "Clients are available for most platforms. Click \"Learn more...\" above " +#| "for recommended clients and instructions on how to configure them." msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" "要连接到 %(box_name)s 的VPN,您需要下载配置文件并将其提供给移动或桌面计算机上" "的 OpenVPN 客户端。OpenVPN 客户端适用于大多数平台。要查看推荐的客户端及配置说" "明请点击上方的 “了解更多…”。" -#: plinth/modules/openvpn/templates/openvpn.html:35 -#, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +#: plinth/modules/openvpn/templates/openvpn.html:24 +#, fuzzy, python-format +#| msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "配置文件是特定于每个 %(box_name)s 用户的。请保持其私密。" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "下载我的配置文件" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4604,34 +4558,34 @@ msgstr "" "PageKite 是一种在您没有直接连接到互联网时暴露 {box_name} 服务的系统。 如果您" "的 {box_name} 服务无法从互联网访问,您只需要设置 PageKite。这包括以下情况:" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "{box_name} 位于受限的防火墙的后面。" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "{box_name} 已连接到非你控制的(无线)路由器。" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "您的 ISP 没有提供外部的 IP 地址而是通过提供 NAT 连接互联网。" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" "您的 ISP 不提供你一个静态的 IP 地址,每次连接到互联网时 IP 地址都会更改。" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "您的 ISP 限制传入的连接。" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4643,23 +4597,23 @@ msgstr "" "使用任何 pagekite 服务提供商,例如pagekite." "net。将来,您或许可以使用好友的 {box_name} 来使用此服务。" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "PageKite" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "公开可见性" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "PageKite 域名" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "服务器域" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." @@ -4667,65 +4621,65 @@ msgstr "" "选择您的 pagekite 服务器。设置\"pagekite.net\"以便使用默认的 pagekite.net 服" "务器。" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "服务器端口" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "你 pagekite 服务器的端口 (默认: 80)" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "Kite 名字" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "示例: mybox.pagekite.me" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "无效的 Kite 名称" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "Kite 密码" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "为 kite 设置的密码,如果没有为 kite 设置密码则会使用你账号的默认密码。" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "协议" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "外网(前端)端口" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "内网(freedombox)端口" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "启用子域" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "删除自定义服务" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "此服务已作为标准服务提供。" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "已添加的自定义服务" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "此服务已存在" @@ -4761,29 +4715,29 @@ msgstr "" "警告:
您的 PageKite 前端服务器可能不支持您在此处定义的所有协议/端" "口组合。例如,已知443以外的端口上的HTTPS会导致问题。" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "Web 服务器(HTTP)" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "网站可从 http://{0} 访问" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "Web 服务器(HTTPS)" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "网站可从 https://{0} 访问" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "安全 Shell(SSH)" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4827,8 +4781,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "重新启动" @@ -4871,6 +4825,39 @@ msgstr "" msgid "Shut Down Now" msgstr "现在关闭" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +#, fuzzy +#| msgid "Privoxy" +msgid "Privacy" +msgstr "Privoxy" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4908,7 +4895,7 @@ msgstr "Web 代理" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "在 tcp{kind} 上通过 {proxy} 访问 {url}" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4923,7 +4910,7 @@ msgstr "" "以运行 Quassel 核心服务,使您始终在线,并且可以使用桌面或移动设备上的一个或多" "个 Quassel 客户端连接和断开连接。" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your 桌面移动设备客户端连接到 Quassel 的核心。" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "IRC 客户端" @@ -4946,7 +4933,7 @@ msgstr "IRC 客户端" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4960,19 +4947,19 @@ msgstr "" "html#documentation/#idcaldav-and-carddavsupported-clients\">支持的客户端应用" "程序。任何拥有 {box_name} 登录名的用户都可以访问 Radicale。" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "日历和通讯录" @@ -5033,7 +5020,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "访问权配置已更新" @@ -5112,7 +5099,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5125,13 +5112,13 @@ msgstr "RSS-Bridge" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5140,31 +5127,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "网络文件存储" @@ -5242,15 +5229,15 @@ msgstr "共享名称" msgid "Action" msgstr "操作" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "FreedomBox 操作系统盘" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "打开共享" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "群组共享" @@ -5276,51 +5263,51 @@ msgstr "已禁用共享。" msgid "Error disabling share: {error_message}" msgstr "禁用共享出错:{error_message}" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "Web 搜索" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "安全搜索" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "中等" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5475,14 +5462,14 @@ msgstr "书签" msgid "Shaarlier" msgstr "Shaarlier" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5491,97 +5478,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "服务器" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "服务器端口" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "共享" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "公共分享" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "已存在同名共享。" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5618,19 +5605,19 @@ msgstr "已添加共享。" msgid "Add Share" msgstr "添加共享" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "已编辑共享。" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "编辑共享" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "已删除共享。" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " @@ -5639,7 +5626,7 @@ msgstr "" "快照可以允许创建并管理 btrfs 文件系统快照。这些可以用来回滚系统到前一个已知可" "用的状态,以防意外改变系统状态。" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5647,14 +5634,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "存储快照" @@ -5748,7 +5735,7 @@ msgstr "日期" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "删除快照" @@ -5798,57 +5785,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "回滚到快照 #%(number)s" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "已手动创建" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "管理快照" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "创建快照。" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "存储快照配置已更新" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "操作错误:{0} [{1}] [{2}]" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "已删除选定的快照" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "回滚到快照 #{number}。" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "系统需要重启以完成完全回滚。" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "回滚到快照" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5856,7 +5843,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "安全 Shell(SSH)服务器" @@ -5889,14 +5876,6 @@ msgstr "" msgid "Fingerprint" msgstr "指纹" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "启用密码的 SSH 身份验证。" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5909,7 +5888,7 @@ msgstr "登录" msgid "Logged out successfully." msgstr "已成功退出登录。" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5917,143 +5896,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "存储" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "{disk_size:.1f} 字节" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "{disk_size:.1f} KiB" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "{disk_size:.1f} MiB" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "{disk_size:.1f} GiB" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "{disk_size:.1f} TiB" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "已经在卸载设备。" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "已挂载此设备。" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "此设备未挂载。" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "无效的目录名。" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "路径不是一个目录。" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "目录" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "共享" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -6089,7 +6068,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "扩展根分区" @@ -6109,30 +6088,30 @@ msgstr "" "执行前请备份你的数据。这个操作以后,将会为你的根分区扩展出 " "%(expandable_root_size)s 空余空间。" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "扩展分区错误:{exception}" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "已成功扩展分区。" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6140,7 +6119,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6152,20 +6131,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "管理 Syncthing 程序" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6178,47 +6157,47 @@ msgstr "" "href=\"https://www.torproject.org/download/download-easy.html.en\">Tor浏览器" "。" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "你的 {box_name} 有一个 Tor SOCKS 端口在 TCP 端口 9050 上对内网可用。" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "Tor 洋葱服务" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "Tor 网桥中继" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "Tor 中继端口可用" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "已注册 Obfs3 传输" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "已注册 Obfs4 传输" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "在 tcp{kind} 上通过 Tor 访问 {url}" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "确认使用 Tor 通过 tcp{kind} 访问 {url}" @@ -6324,11 +6303,11 @@ msgstr "洋葱服务" msgid "Ports" msgstr "端口" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 msgid "Updating configuration" msgstr "更新配置" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, python-brace-format msgid "Error configuring app: {error}" msgstr "配置应用出错:{error}" @@ -6382,7 +6361,7 @@ msgstr "" msgid "Transmission" msgstr "Transmission" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " @@ -6391,7 +6370,7 @@ msgstr "" "Tiny Tiny RSS是一个新闻源(RSS / Atom)阅读器和聚合器,旨在允许从任何位置读取" "新闻,同时提供尽可能接近真实的桌面应用程序体验。" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, python-brace-format msgid "" "When enabled, Tiny Tiny RSS can be accessed by any " @@ -6400,17 +6379,17 @@ msgstr "" "启用后,属于该订阅源阅读器群的 任何用户均可访问 " "Tiny Tiny RSS。" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "新闻源阅读器" @@ -6418,12 +6397,12 @@ msgstr "新闻源阅读器" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "检查并应用最新软件和安全更新。" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6431,33 +6410,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "软件更新" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "FreedomBox 已更新" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "已启动分发更新" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6612,51 +6591,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "立即测试分发升级" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "配置无人参与升级时错误:{error}" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "已启用自动升级" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "已禁用自动升级" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "已启用分发升级" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "已禁用分发升级" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "升级过程开始。" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "开始升级失败。" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "启动分发升级测试。" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6664,15 +6643,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "用户和组" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "请检查 LDAP 条目“{search_item}”" @@ -6690,21 +6669,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "验证密码" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "密码无效。" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6716,12 +6695,12 @@ msgstr "" "单点登录的服务。

管理员(admin)组中的用户将能够登录所有服务。他们还可" "以通过 SSH 登录到系统并具有管理权限(sudo)。" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "创建 LDAP 用户失败:{error}" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "未能将新用户添加到 {group} 组:{error}" @@ -6739,41 +6718,41 @@ msgstr "" "设置 SSH 公钥将允许此用户安全地登录到系统不使用密码。您可以输入多个密钥,每行" "一个。将忽略空行和以 # 开头的行。" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "重命名 LDAP 用户失败。" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "无法从组中删除用户。" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "无法将用户添加到组。" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "不能设置 SSH 密钥。" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "更改用户状态失败。" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "更改 LDAP 用户密码失败。" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "未能将新用户添加到管理员组:{error}" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "限制控制台访问失败:{error}" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "用户帐户已创建,您现在可以登录" @@ -6790,12 +6769,12 @@ msgstr "保存密码" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "创建用户" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "删除用户" @@ -6835,17 +6814,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "用户" @@ -6876,34 +6855,34 @@ msgstr "使用 更改密码表单 更改 msgid "Save Changes" msgstr "保存更改" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "用户 %(username)s 已创建。" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "用户 %(username)s 已更新。" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "编辑用户" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "用户 {user} 已删除。" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "删除 LDAP 用户失败。" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "更改密码" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "已成功更改密码。" @@ -7212,7 +7191,7 @@ msgstr "删除与服务器的连接" msgid "Server deleted." msgstr "服务器已删除。" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7221,7 +7200,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7230,26 +7209,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "WordPress" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "网站和博客" @@ -7263,7 +7242,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7276,7 +7255,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7284,11 +7263,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7337,96 +7316,92 @@ msgstr "" msgid "Finished: {name}" msgstr "已完成:{name}" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -msgid "Error running apt-get" -msgstr "运行 apt-get 出错" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "安装" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "下载中" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "媒体改变" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "配置文件:{file}" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "安装应用中" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "安装应用出错:{string} {details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "更新应用出错:{string} {details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, python-brace-format msgid "Error installing app: {error}" msgstr "安装应用出错:{error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, python-brace-format msgid "Error updating app: {error}" msgstr "更新应用出错:{error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 msgid "App installed." msgstr "应用已安装。" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "应用已更新" -#: plinth/setup.py:104 +#: plinth/setup.py:105 msgid "Uninstalling app" msgstr "卸载应用" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "卸载应用出错:{string} {details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "卸载应用出错:{error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 msgid "App uninstalled." msgstr "应用已卸载。" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "更新软件包中" @@ -7484,53 +7459,54 @@ msgstr "安装" msgid "Service %(service_name)s is not running." msgstr "服务 %(service_name)s 未在运行。" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "%(box_name)s 的核心功能和网络界面" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." +msgstr "" -#: plinth/templates/base.html:107 +#: plinth/templates/base.html:110 msgid " Home" msgstr " 主页" -#: plinth/templates/base.html:110 +#: plinth/templates/base.html:113 msgid "Home" msgstr "主页" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr " 应用程序" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "应用程序" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr " 系统" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "系统" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "更改密码" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "关闭" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "登出" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "选择语言" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "登录" @@ -7797,6 +7773,37 @@ msgstr "" msgid "Gujarati" msgstr "古吉拉特语" +#~ msgid "Enable DNSSEC" +#~ msgstr "启用 DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "启用域名系统安全扩展(DNSSEC)" + +#, python-format +#~ msgid "" +#~ "Firewall daemon is not running. Please run it. Firewall comes enabled by " +#~ "default on %(box_name)s. On any Debian based system (such as " +#~ "%(box_name)s) you may run it using the command 'service firewalld start' " +#~ "or in case of a system with systemd 'systemctl start firewalld'." +#~ msgstr "" +#~ "防火墙守护程序未运行。请运行它。防火墙默认在 %(box_name)s 上启用。在任何基" +#~ "于 Debian 的系统(例如 %(box_name)s)上,要运行它,您可以使用命令 " +#~ "“service firewalld start” ,在使用 systemd 的系统上则使用 “systemctl " +#~ "start firewalld”命令。" + +#~ msgid "Migrate" +#~ msgstr "迁移" + +#~ msgid "SSH authentication with password enabled." +#~ msgstr "启用密码的 SSH 身份验证。" + +#~ msgid "Error running apt-get" +#~ msgstr "运行 apt-get 出错" + +#, python-format +#~ msgid "Core functionality and web interface for %(box_name)s" +#~ msgstr "%(box_name)s 的核心功能和网络界面" + #~ msgid "Network Connections" #~ msgstr "网络连接" diff --git a/plinth/locale/zh_Hant/LC_MESSAGES/django.po b/plinth/locale/zh_Hant/LC_MESSAGES/django.po index e3dab660a..2581b4a9c 100644 --- a/plinth/locale/zh_Hant/LC_MESSAGES/django.po +++ b/plinth/locale/zh_Hant/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-26 19:51-0400\n" +"POT-Creation-Date: 2022-10-10 21:35-0400\n" "PO-Revision-Date: 2021-12-23 12:50+0000\n" "Last-Translator: pesder \n" "Language-Team: Chinese (Traditional) calibre group will be able to access the " "app. All users with access can use all the libraries." @@ -1008,29 +1001,29 @@ msgstr "" "只有屬於 calibre 群組的使用者可以存取這個 app。每個能存取的使用者都" "可以使用所有的圖書館。" -#: plinth/modules/calibre/__init__.py:55 +#: plinth/modules/calibre/__init__.py:51 msgid "Use calibre e-book libraries" msgstr "使用 calibre 電子書庫" -#: plinth/modules/calibre/__init__.py:58 plinth/modules/calibre/manifest.py:6 +#: plinth/modules/calibre/__init__.py:54 plinth/modules/calibre/manifest.py:6 msgid "calibre" msgstr "calibre" -#: plinth/modules/calibre/__init__.py:59 +#: plinth/modules/calibre/__init__.py:55 msgid "E-book Library" msgstr "電子書圖書館" -#: plinth/modules/calibre/forms.py:18 +#: plinth/modules/calibre/forms.py:16 msgid "Name of the new library" msgstr "新圖書館名稱" -#: plinth/modules/calibre/forms.py:19 +#: plinth/modules/calibre/forms.py:17 msgid "" "Only letters of the English alphabet, numbers and the characters _ . and - " "without spaces or special characters. Example: My_Library_2000" msgstr "" -#: plinth/modules/calibre/forms.py:30 +#: plinth/modules/calibre/forms.py:28 msgid "A library with this name already exists." msgstr "已存在同樣名稱的圖書館。" @@ -1076,20 +1069,20 @@ msgstr "前往至圖書館 %(library)s" msgid "Delete library %(library)s" msgstr "刪除圖書館 %(library)s" -#: plinth/modules/calibre/views.py:41 +#: plinth/modules/calibre/views.py:39 msgid "Library created." msgstr "圖書已建立。" -#: plinth/modules/calibre/views.py:52 +#: plinth/modules/calibre/views.py:49 msgid "An error occurred while creating the library." msgstr "建立圖書館時發生錯誤。" -#: plinth/modules/calibre/views.py:66 plinth/modules/gitweb/views.py:143 +#: plinth/modules/calibre/views.py:63 plinth/modules/gitweb/views.py:139 #, python-brace-format msgid "{name} deleted." msgstr "{name} 已刪除。" -#: plinth/modules/calibre/views.py:70 plinth/modules/gitweb/views.py:147 +#: plinth/modules/calibre/views.py:67 plinth/modules/gitweb/views.py:143 #, python-brace-format msgid "Could not delete {name}: {error}" msgstr "無法刪除 {name}: {error}" @@ -1134,7 +1127,7 @@ msgstr "Cockpit" msgid "Server Administration" msgstr "伺服器管理" -#: plinth/modules/config/__init__.py:25 +#: plinth/modules/config/__init__.py:22 msgid "" "Here you can set some general configuration options like hostname, domain " "name, webserver home page etc." @@ -1142,18 +1135,18 @@ msgstr "" "在這裡您可以設定某些一般設定選項,像是主機名稱、網域名稱、網頁伺服器首頁等" "等。" -#: plinth/modules/config/__init__.py:53 +#: plinth/modules/config/__init__.py:44 msgid "General Configuration" msgstr "一般配置" -#: plinth/modules/config/__init__.py:58 +#: plinth/modules/config/__init__.py:49 #: plinth/modules/names/templates/names.html:30 #: plinth/modules/names/templates/names.html:44 -#: plinth/modules/snapshot/views.py:37 plinth/templates/index.html:38 +#: plinth/modules/snapshot/views.py:32 plinth/templates/index.html:38 msgid "Configure" msgstr "配置" -#: plinth/modules/config/__init__.py:71 plinth/modules/config/forms.py:68 +#: plinth/modules/config/__init__.py:62 plinth/modules/config/forms.py:68 #: plinth/modules/dynamicdns/forms.py:82 #: plinth/modules/names/templates/names.html:16 msgid "Domain Name" @@ -1259,47 +1252,47 @@ msgid "" "from various services" msgstr "" -#: plinth/modules/config/views.py:50 +#: plinth/modules/config/views.py:49 #, python-brace-format msgid "Error setting hostname: {exception}" msgstr "設定主機名稱時發生錯誤︰{exception}" -#: plinth/modules/config/views.py:53 +#: plinth/modules/config/views.py:52 msgid "Hostname set" msgstr "主機名稱設定" -#: plinth/modules/config/views.py:62 +#: plinth/modules/config/views.py:61 #, python-brace-format msgid "Error setting domain name: {exception}" msgstr "設定網域名稱時發生錯誤︰{exception}" -#: plinth/modules/config/views.py:65 +#: plinth/modules/config/views.py:64 msgid "Domain name set" msgstr "網域名稱設定" -#: plinth/modules/config/views.py:73 +#: plinth/modules/config/views.py:72 #, python-brace-format msgid "Error setting webserver home page: {exception}" msgstr "設定網頁伺服器首頁時發生錯誤︰{exception}" -#: plinth/modules/config/views.py:76 +#: plinth/modules/config/views.py:75 msgid "Webserver home page set" msgstr "網頁伺服器首頁設定" -#: plinth/modules/config/views.py:84 +#: plinth/modules/config/views.py:83 #, python-brace-format msgid "Error changing advanced mode: {exception}" msgstr "改變進階模式時發生錯誤︰{exception}" -#: plinth/modules/config/views.py:89 +#: plinth/modules/config/views.py:88 msgid "Showing advanced apps and features" msgstr "顯示進階 app 與功能" -#: plinth/modules/config/views.py:92 +#: plinth/modules/config/views.py:91 msgid "Hiding advanced apps and features" msgstr "隱藏進階 app 與功能" -#: plinth/modules/coturn/__init__.py:29 +#: plinth/modules/coturn/__init__.py:25 msgid "" "Coturn is a server to facilitate audio/video calls and conferences by " "providing an implementation of TURN and STUN protocols. WebRTC, SIP and " @@ -1310,7 +1303,7 @@ msgstr "" "和會議。 WebRTC、SIP 和其他通訊伺服器可以使用它在無法相互連接的各方之間建立通" "訊。" -#: plinth/modules/coturn/__init__.py:34 +#: plinth/modules/coturn/__init__.py:30 #, python-brace-format msgid "" "It is not meant to be used directly by users. Servers such as Matrix Synapse " "或 ejabberd 都需要以在這裡提供的資料來設定。" -#: plinth/modules/coturn/__init__.py:56 +#: plinth/modules/coturn/__init__.py:52 msgid "Coturn" msgstr "Coturn" -#: plinth/modules/coturn/__init__.py:57 +#: plinth/modules/coturn/__init__.py:53 msgid "VoIP Helper" msgstr "VoIP 協助程式" @@ -1377,26 +1370,26 @@ msgstr "設定時區時發生錯誤︰{exception}" msgid "Time zone set" msgstr "時區設定" -#: plinth/modules/deluge/__init__.py:22 +#: plinth/modules/deluge/__init__.py:19 msgid "Deluge is a BitTorrent client that features a Web UI." msgstr "Deluge 是一個具有網頁使用者介面的 BitTorrent 客戶端。" -#: plinth/modules/deluge/__init__.py:23 +#: plinth/modules/deluge/__init__.py:20 msgid "" "The default password is 'deluge', but you should log in and change it " "immediately after enabling this service." msgstr "預設的密碼是「deluge」,但啟用這個服務後您應該登入並立即改變它。" -#: plinth/modules/deluge/__init__.py:42 +#: plinth/modules/deluge/__init__.py:39 #: plinth/modules/transmission/__init__.py:62 msgid "Download files using BitTorrent applications" msgstr "使用 BitTorrent 應用程式下載檔案" -#: plinth/modules/deluge/__init__.py:46 plinth/modules/deluge/manifest.py:6 +#: plinth/modules/deluge/__init__.py:43 plinth/modules/deluge/manifest.py:6 msgid "Deluge" msgstr "Deluge" -#: plinth/modules/deluge/__init__.py:48 +#: plinth/modules/deluge/__init__.py:45 #: plinth/modules/transmission/__init__.py:68 msgid "BitTorrent Web Client" msgstr "BitTorrent 網頁客戶端" @@ -1515,7 +1508,7 @@ msgstr "" msgid "Diagnostic Test" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:29 +#: plinth/modules/dynamicdns/__init__.py:28 #, python-brace-format msgid "" "If your Internet provider changes your IP address periodically (i.e. every " @@ -1523,7 +1516,7 @@ msgid "" "prevent others from finding services which are provided by this {box_name}." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:33 +#: plinth/modules/dynamicdns/__init__.py:32 msgid "" "The solution is to assign a DNS name to your IP address and update the DNS " "name every time your IP is changed by your Internet provider. Dynamic DNS " @@ -1534,7 +1527,7 @@ msgid "" "IP address." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:41 +#: plinth/modules/dynamicdns/__init__.py:40 msgid "" "If you are looking for a free dynamic DNS account, you may find a free " "GnuDIP service at ddns." @@ -1542,11 +1535,11 @@ msgid "" "href='http://freedns.afraid.org/' target='_blank'>freedns.afraid.org." msgstr "" -#: plinth/modules/dynamicdns/__init__.py:62 +#: plinth/modules/dynamicdns/__init__.py:61 msgid "Dynamic DNS Client" msgstr "" -#: plinth/modules/dynamicdns/__init__.py:75 +#: plinth/modules/dynamicdns/__init__.py:74 msgid "Dynamic Domain Name" msgstr "" @@ -1658,7 +1651,7 @@ msgstr "" #: plinth/modules/dynamicdns/templates/dynamicdns.html:11 #: plinth/modules/ejabberd/templates/ejabberd.html:13 #: plinth/modules/firewall/templates/firewall.html:16 -#: plinth/modules/firewall/templates/firewall.html:36 +#: plinth/modules/firewall/templates/firewall.html:22 #: plinth/modules/letsencrypt/templates/letsencrypt.html:17 #: plinth/modules/matrixsynapse/templates/matrix-synapse.html:12 #: plinth/modules/networks/templates/connection_show.html:254 @@ -1721,13 +1714,13 @@ msgstr "" msgid "Already up-to-date" msgstr "" -#: plinth/modules/ejabberd/__init__.py:31 +#: plinth/modules/ejabberd/__init__.py:29 msgid "" "XMPP is an open and standardized communication protocol. Here you can run " "and configure your XMPP server, called ejabberd." msgstr "" -#: plinth/modules/ejabberd/__init__.py:34 +#: plinth/modules/ejabberd/__init__.py:32 #, python-brace-format msgid "" "To actually communicate, you can use the web client user with a {box_name} login." msgstr "" -#: plinth/modules/ejabberd/__init__.py:42 +#: plinth/modules/ejabberd/__init__.py:40 #, python-brace-format msgid "" "ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server." msgstr "" -#: plinth/modules/ejabberd/__init__.py:63 +#: plinth/modules/ejabberd/__init__.py:61 msgid "ejabberd" msgstr "" -#: plinth/modules/ejabberd/__init__.py:64 -#: plinth/modules/matrixsynapse/__init__.py:69 +#: plinth/modules/ejabberd/__init__.py:62 +#: plinth/modules/matrixsynapse/__init__.py:56 msgid "Chat Server" msgstr "" @@ -1851,14 +1844,14 @@ msgid "" "Configure page." msgstr "" -#: plinth/modules/email/__init__.py:26 +#: plinth/modules/email/__init__.py:25 msgid "" "This is a complete email server solution using Postfix, Dovecot, and Rspamd. " "Postfix sends and receives emails. Dovecot allows email clients to access " "your mailbox using IMAP and POP3. Rspamd deals with spam." msgstr "" -#: plinth/modules/email/__init__.py:30 +#: plinth/modules/email/__init__.py:29 msgid "" "Email server currently does not work with many free domain services " "including those provided by the FreedomBox Foundation. Many ISPs also " @@ -1866,7 +1859,7 @@ msgid "" "request. See manual page for more information." msgstr "" -#: plinth/modules/email/__init__.py:35 +#: plinth/modules/email/__init__.py:34 #, python-brace-format msgid "" "Each user on {box_name} gets an email address like user@mydomain.example. " @@ -1876,13 +1869,13 @@ msgid "" "to the first admin user." msgstr "" -#: plinth/modules/email/__init__.py:41 +#: plinth/modules/email/__init__.py:40 msgid "" "Roundcube app provides web interface " "for users to access email." msgstr "" -#: plinth/modules/email/__init__.py:43 +#: plinth/modules/email/__init__.py:42 msgid "" "During installation, any other email servers in the system will be " "uninstalled." @@ -2021,7 +2014,7 @@ msgstr "" msgid "Host/Target/Value" msgstr "" -#: plinth/modules/firewall/__init__.py:26 +#: plinth/modules/firewall/__init__.py:23 #, python-brace-format msgid "" "Firewall is a security system that controls the incoming and outgoing " @@ -2029,7 +2022,7 @@ msgid "" "configured reduces risk of security threat from the Internet." msgstr "" -#: plinth/modules/firewall/__init__.py:60 +#: plinth/modules/firewall/__init__.py:57 msgid "Firewall" msgstr "" @@ -2049,61 +2042,52 @@ msgid "Port {name} ({details}) unavailable for external networks" msgstr "" #: plinth/modules/firewall/templates/firewall.html:21 -#, python-format -msgid "" -"Firewall daemon is not running. Please run it. Firewall comes enabled by " -"default on %(box_name)s. On any Debian based system (such as %(box_name)s) " -"you may run it using the command 'service firewalld start' or in case of a " -"system with systemd 'systemctl start firewalld'." -msgstr "" - -#: plinth/modules/firewall/templates/firewall.html:35 msgid "Service/Port" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:54 +#: plinth/modules/firewall/templates/firewall.html:40 #: plinth/modules/letsencrypt/templates/letsencrypt.html:69 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 msgid "Enabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:57 +#: plinth/modules/firewall/templates/firewall.html:43 #: plinth/modules/letsencrypt/templates/letsencrypt.html:71 #: plinth/modules/snapshot/forms.py:23 plinth/modules/snapshot/forms.py:29 #: plinth/templates/cards.html:34 msgid "Disabled" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:72 +#: plinth/modules/firewall/templates/firewall.html:58 msgid "Permitted" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:75 +#: plinth/modules/firewall/templates/firewall.html:61 msgid "Permitted (internal only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:78 +#: plinth/modules/firewall/templates/firewall.html:64 msgid "Permitted (external only)" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:81 +#: plinth/modules/firewall/templates/firewall.html:67 msgid "Blocked" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:94 +#: plinth/modules/firewall/templates/firewall.html:80 msgid "" "The operation of the firewall is automatic. When you enable a service it is " "also permitted in the firewall and when you disable a service it is also " "disabled in the firewall." msgstr "" -#: plinth/modules/firewall/templates/firewall.html:102 +#: plinth/modules/firewall/templates/firewall.html:88 #: plinth/modules/networks/templates/networks_configuration.html:22 #: plinth/modules/storage/templates/storage.html:93 msgid "Advanced" msgstr "" -#: plinth/modules/firewall/templates/firewall.html:104 +#: plinth/modules/firewall/templates/firewall.html:90 msgid "" "Advanced firewall operations such as opening custom ports are provided by " "the Cockpit app." @@ -2149,7 +2133,7 @@ msgstr "" msgid "Setup Complete" msgstr "" -#: plinth/modules/gitweb/__init__.py:26 +#: plinth/modules/gitweb/__init__.py:21 msgid "" "Git is a distributed version-control system for tracking changes in source " "code during software development. Gitweb provides a web interface to Git " @@ -2160,73 +2144,73 @@ msgid "" "the world." msgstr "" -#: plinth/modules/gitweb/__init__.py:33 +#: plinth/modules/gitweb/__init__.py:28 msgid "" "To learn more on how to use Git visit Git tutorial." msgstr "" -#: plinth/modules/gitweb/__init__.py:49 +#: plinth/modules/gitweb/__init__.py:44 msgid "Read-write access to Git repositories" msgstr "" -#: plinth/modules/gitweb/__init__.py:54 plinth/modules/gitweb/manifest.py:10 +#: plinth/modules/gitweb/__init__.py:49 plinth/modules/gitweb/manifest.py:10 msgid "Gitweb" msgstr "" -#: plinth/modules/gitweb/__init__.py:55 +#: plinth/modules/gitweb/__init__.py:50 msgid "Simple Git Hosting" msgstr "" -#: plinth/modules/gitweb/forms.py:59 +#: plinth/modules/gitweb/forms.py:58 msgid "Invalid repository URL." msgstr "" -#: plinth/modules/gitweb/forms.py:69 +#: plinth/modules/gitweb/forms.py:68 msgid "Invalid repository name." msgstr "" -#: plinth/modules/gitweb/forms.py:77 +#: plinth/modules/gitweb/forms.py:76 msgid "Name of a new repository or URL to import an existing repository." msgstr "" -#: plinth/modules/gitweb/forms.py:83 +#: plinth/modules/gitweb/forms.py:82 msgid "Description of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88 +#: plinth/modules/gitweb/forms.py:83 plinth/modules/gitweb/forms.py:87 msgid "Optional, for displaying on Gitweb." msgstr "" -#: plinth/modules/gitweb/forms.py:86 +#: plinth/modules/gitweb/forms.py:85 msgid "Repository's owner name" msgstr "" -#: plinth/modules/gitweb/forms.py:91 +#: plinth/modules/gitweb/forms.py:90 msgid "Private repository" msgstr "" -#: plinth/modules/gitweb/forms.py:92 +#: plinth/modules/gitweb/forms.py:91 msgid "Allow only authorized users to access this repository." msgstr "" -#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155 +#: plinth/modules/gitweb/forms.py:112 plinth/modules/gitweb/forms.py:154 msgid "A repository with this name already exists." msgstr "" -#: plinth/modules/gitweb/forms.py:126 +#: plinth/modules/gitweb/forms.py:125 msgid "Name of the repository" msgstr "" -#: plinth/modules/gitweb/forms.py:130 +#: plinth/modules/gitweb/forms.py:129 msgid "An alpha-numeric string that uniquely identifies a repository." msgstr "" -#: plinth/modules/gitweb/forms.py:134 +#: plinth/modules/gitweb/forms.py:133 msgid "Default branch" msgstr "" -#: plinth/modules/gitweb/forms.py:135 +#: plinth/modules/gitweb/forms.py:134 msgid "Gitweb displays this as a default branch." msgstr "" @@ -2270,19 +2254,19 @@ msgstr "" msgid "Delete this repository permanently?" msgstr "" -#: plinth/modules/gitweb/views.py:49 +#: plinth/modules/gitweb/views.py:46 msgid "Repository created." msgstr "" -#: plinth/modules/gitweb/views.py:73 +#: plinth/modules/gitweb/views.py:69 msgid "An error occurred while creating the repository." msgstr "" -#: plinth/modules/gitweb/views.py:88 +#: plinth/modules/gitweb/views.py:84 msgid "Repository edited." msgstr "" -#: plinth/modules/gitweb/views.py:93 +#: plinth/modules/gitweb/views.py:89 msgid "Edit repository" msgstr "" @@ -2575,7 +2559,7 @@ msgstr "" msgid "{box_name} Manual" msgstr "" -#: plinth/modules/i2p/__init__.py:22 +#: plinth/modules/i2p/__init__.py:19 msgid "" "The Invisible Internet Project is an anonymous network layer intended to " "protect communication from censorship and surveillance. I2P provides " @@ -2583,31 +2567,31 @@ msgid "" "distributed around the world." msgstr "" -#: plinth/modules/i2p/__init__.py:26 +#: plinth/modules/i2p/__init__.py:23 msgid "" "Find more information about I2P on their project homepage." msgstr "" -#: plinth/modules/i2p/__init__.py:28 +#: plinth/modules/i2p/__init__.py:25 msgid "" "The first visit to the provided web interface will initiate the " "configuration process." msgstr "" -#: plinth/modules/i2p/__init__.py:50 +#: plinth/modules/i2p/__init__.py:47 msgid "Manage I2P application" msgstr "" -#: plinth/modules/i2p/__init__.py:53 plinth/modules/i2p/manifest.py:13 +#: plinth/modules/i2p/__init__.py:50 plinth/modules/i2p/manifest.py:13 msgid "I2P" msgstr "" -#: plinth/modules/i2p/__init__.py:54 plinth/modules/tor/__init__.py:53 +#: plinth/modules/i2p/__init__.py:51 plinth/modules/tor/__init__.py:49 msgid "Anonymity Network" msgstr "" -#: plinth/modules/i2p/__init__.py:80 +#: plinth/modules/i2p/__init__.py:77 msgid "I2P Proxy" msgstr "" @@ -2644,14 +2628,14 @@ msgid "" "a file." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:22 +#: plinth/modules/ikiwiki/__init__.py:19 msgid "" "ikiwiki is a simple wiki and blog application. It supports several " "lightweight markup languages, including Markdown, and common blogging " "functionality such as comments and RSS feeds." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:26 +#: plinth/modules/ikiwiki/__init__.py:23 #, python-brace-format msgid "" "Only {box_name} users in the admin group can create and " @@ -2660,15 +2644,15 @@ msgid "" "Configuration you can change these permissions or add new users." msgstr "" -#: plinth/modules/ikiwiki/__init__.py:47 plinth/modules/ikiwiki/manifest.py:6 +#: plinth/modules/ikiwiki/__init__.py:44 plinth/modules/ikiwiki/manifest.py:6 msgid "ikiwiki" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:48 +#: plinth/modules/ikiwiki/__init__.py:45 msgid "Wiki and Blog" msgstr "" -#: plinth/modules/ikiwiki/__init__.py:75 +#: plinth/modules/ikiwiki/__init__.py:72 msgid "View and edit wiki applications" msgstr "" @@ -2722,41 +2706,41 @@ msgid "" "history. Delete this wiki or blog permanently?" msgstr "" -#: plinth/modules/ikiwiki/views.py:74 +#: plinth/modules/ikiwiki/views.py:69 #, python-brace-format msgid "Created wiki {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:77 +#: plinth/modules/ikiwiki/views.py:72 #, python-brace-format msgid "Could not create wiki: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:87 +#: plinth/modules/ikiwiki/views.py:79 #, python-brace-format msgid "Created blog {name}." msgstr "" -#: plinth/modules/ikiwiki/views.py:90 +#: plinth/modules/ikiwiki/views.py:82 #, python-brace-format msgid "Could not create blog: {error}" msgstr "" -#: plinth/modules/ikiwiki/views.py:106 +#: plinth/modules/ikiwiki/views.py:98 #, python-brace-format msgid "{title} deleted." msgstr "" -#: plinth/modules/ikiwiki/views.py:110 +#: plinth/modules/ikiwiki/views.py:102 #, python-brace-format msgid "Could not delete {title}: {error}" msgstr "" -#: plinth/modules/infinoted/__init__.py:21 +#: plinth/modules/infinoted/__init__.py:20 msgid "infinoted is a server for Gobby, a collaborative text editor." msgstr "" -#: plinth/modules/infinoted/__init__.py:23 +#: plinth/modules/infinoted/__init__.py:22 #, python-brace-format msgid "" "To use it, download Gobby, desktop " @@ -2764,11 +2748,11 @@ msgid "" "enter your {box_name}'s domain name." msgstr "" -#: plinth/modules/infinoted/__init__.py:42 +#: plinth/modules/infinoted/__init__.py:41 msgid "infinoted" msgstr "" -#: plinth/modules/infinoted/__init__.py:43 +#: plinth/modules/infinoted/__init__.py:42 msgid "Gobby Server" msgstr "" @@ -2814,7 +2798,7 @@ msgstr "" #: plinth/modules/janus/templates/janus_video_room.html:205 #: plinth/modules/jsxc/templates/jsxc_launch.html:117 -#: plinth/templates/base.html:247 +#: plinth/templates/base.html:250 msgid "JavaScript license information" msgstr "" @@ -2832,7 +2816,7 @@ msgstr "" msgid "Chat Client" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:28 +#: plinth/modules/letsencrypt/__init__.py:24 #, python-brace-format msgid "" "A digital certificate allows users of a web service to verify the identity " @@ -2842,7 +2826,7 @@ msgid "" "Encrypt, a certificate authority (CA)." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:34 +#: plinth/modules/letsencrypt/__init__.py:30 msgid "" "Let's Encrypt is a free, automated, and open certificate authority, run for " "the public's benefit by the Internet Security Research Group (ISRG). Please " @@ -2850,15 +2834,15 @@ msgid "" "\">Let's Encrypt Subscriber Agreement before using this service." msgstr "" -#: plinth/modules/letsencrypt/__init__.py:61 +#: plinth/modules/letsencrypt/__init__.py:57 msgid "Let's Encrypt" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:62 +#: plinth/modules/letsencrypt/__init__.py:58 msgid "Certificates" msgstr "" -#: plinth/modules/letsencrypt/__init__.py:98 +#: plinth/modules/letsencrypt/__init__.py:94 msgid "Cannot test: No domains are configured." msgstr "" @@ -2921,41 +2905,41 @@ msgid "" "domains to be able to obtain certificates for them." msgstr "" -#: plinth/modules/letsencrypt/views.py:41 +#: plinth/modules/letsencrypt/views.py:40 #, python-brace-format msgid "" "Certificate successfully revoked for domain {domain}.This may take a few " "moments to take effect." msgstr "" -#: plinth/modules/letsencrypt/views.py:47 +#: plinth/modules/letsencrypt/views.py:46 #, python-brace-format msgid "Failed to revoke certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:60 -#: plinth/modules/letsencrypt/views.py:77 +#: plinth/modules/letsencrypt/views.py:59 +#: plinth/modules/letsencrypt/views.py:76 #, python-brace-format msgid "Certificate successfully obtained for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:65 -#: plinth/modules/letsencrypt/views.py:82 +#: plinth/modules/letsencrypt/views.py:64 +#: plinth/modules/letsencrypt/views.py:81 #, python-brace-format msgid "Failed to obtain certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/letsencrypt/views.py:94 +#: plinth/modules/letsencrypt/views.py:93 #, python-brace-format msgid "Certificate successfully deleted for domain {domain}" msgstr "" -#: plinth/modules/letsencrypt/views.py:99 +#: plinth/modules/letsencrypt/views.py:98 #, python-brace-format msgid "Failed to delete certificate for domain {domain}: {error}" msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:29 +#: plinth/modules/matrixsynapse/__init__.py:26 msgid "" "Matrix is an new " "ecosystem for open, federated instant messaging and VoIP. Synapse is a " @@ -2965,14 +2949,14 @@ msgid "" "converse with users on all other Matrix servers via federation." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:37 +#: plinth/modules/matrixsynapse/__init__.py:34 #, python-brace-format msgid "" "Matrix Synapse needs a STUN/TURN server for audio/video calls. Install the " "Coturn app or configure an external server." msgstr "" -#: plinth/modules/matrixsynapse/__init__.py:68 +#: plinth/modules/matrixsynapse/__init__.py:55 msgid "Matrix Synapse" msgstr "" @@ -3053,7 +3037,7 @@ msgid "" "go to Let's Encrypt to obtain one." msgstr "" -#: plinth/modules/mediawiki/__init__.py:23 +#: plinth/modules/mediawiki/__init__.py:20 msgid "" "MediaWiki is the wiki engine that powers Wikipedia and other WikiMedia " "projects. A wiki engine is a program for creating a collaboratively edited " @@ -3061,7 +3045,7 @@ msgid "" "collaborate with friends on projects." msgstr "" -#: plinth/modules/mediawiki/__init__.py:27 +#: plinth/modules/mediawiki/__init__.py:24 msgid "" "This MediaWiki instance comes with a randomly generated administrator " "password. You can set a new password in the \"Configuration\" section and " @@ -3070,18 +3054,18 @@ msgid "" "CreateAccount\">Special:CreateAccount page." msgstr "" -#: plinth/modules/mediawiki/__init__.py:33 +#: plinth/modules/mediawiki/__init__.py:30 msgid "" "Anyone with a link to this wiki can read it. Only users that are logged in " "can make changes to the content." msgstr "" -#: plinth/modules/mediawiki/__init__.py:54 +#: plinth/modules/mediawiki/__init__.py:51 #: plinth/modules/mediawiki/manifest.py:6 msgid "MediaWiki" msgstr "" -#: plinth/modules/mediawiki/__init__.py:55 plinth/templates/index.html:124 +#: plinth/modules/mediawiki/__init__.py:52 plinth/templates/index.html:124 msgid "Wiki" msgstr "" @@ -3152,39 +3136,39 @@ msgstr "" msgid "Password update failed. Please choose a stronger password" msgstr "" -#: plinth/modules/mediawiki/views.py:69 +#: plinth/modules/mediawiki/views.py:68 msgid "Public registrations enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:78 +#: plinth/modules/mediawiki/views.py:76 msgid "Public registrations disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:83 +#: plinth/modules/mediawiki/views.py:81 msgid "Private mode enabled" msgstr "" -#: plinth/modules/mediawiki/views.py:90 +#: plinth/modules/mediawiki/views.py:87 msgid "Private mode disabled" msgstr "" -#: plinth/modules/mediawiki/views.py:98 +#: plinth/modules/mediawiki/views.py:95 msgid "Default skin changed" msgstr "" -#: plinth/modules/mediawiki/views.py:102 +#: plinth/modules/mediawiki/views.py:99 #, fuzzy #| msgid "Domain name set" msgid "Domain name updated" msgstr "網域名稱設定" -#: plinth/modules/mediawiki/views.py:106 +#: plinth/modules/mediawiki/views.py:103 #, fuzzy #| msgid "Domain name set" msgid "Site name updated" msgstr "網域名稱設定" -#: plinth/modules/minetest/__init__.py:35 +#: plinth/modules/minetest/__init__.py:33 #, python-brace-format msgid "" "Minetest is a multiplayer infinite-world block sandbox. This module enables " @@ -3193,11 +3177,11 @@ msgid "" "downloads/\">Minetest client is needed." msgstr "" -#: plinth/modules/minetest/__init__.py:58 plinth/modules/minetest/manifest.py:9 +#: plinth/modules/minetest/__init__.py:56 plinth/modules/minetest/manifest.py:9 msgid "Minetest" msgstr "" -#: plinth/modules/minetest/__init__.py:59 +#: plinth/modules/minetest/__init__.py:57 msgid "Block Sandbox" msgstr "" @@ -3242,7 +3226,7 @@ msgstr "" msgid "Address" msgstr "" -#: plinth/modules/minidlna/__init__.py:21 +#: plinth/modules/minidlna/__init__.py:20 msgid "" "MiniDLNA is a simple media server software, with the aim of being fully " "compliant with DLNA/UPnP-AV clients. The MiniDLNA daemon serves media files " @@ -3403,19 +3387,19 @@ msgstr "" msgid "Services" msgstr "" -#: plinth/modules/networks/__init__.py:35 +#: plinth/modules/networks/__init__.py:34 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: plinth/modules/networks/__init__.py:37 +#: plinth/modules/networks/__init__.py:36 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: plinth/modules/networks/__init__.py:58 +#: plinth/modules/networks/__init__.py:57 msgid "Networks" msgstr "" @@ -3761,7 +3745,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:36 #: plinth/modules/wireguard/templates/wireguard_show_client.html:72 #: plinth/modules/wireguard/templates/wireguard_show_server.html:73 -#: plinth/templates/base.html:156 plinth/templates/base.html:157 +#: plinth/templates/base.html:159 plinth/templates/base.html:160 msgid "Edit" msgstr "" @@ -3866,7 +3850,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:175 #: plinth/modules/networks/templates/connection_show.html:218 -#: plinth/modules/shadowsocks/forms.py:49 +#: plinth/modules/shadowsocks/forms.py:48 msgid "Method" msgstr "" @@ -3882,7 +3866,7 @@ msgstr "" #: plinth/modules/networks/templates/connection_show.html:207 #: plinth/modules/networks/templates/connection_show.html:248 -#: plinth/modules/storage/forms.py:138 +#: plinth/modules/storage/forms.py:132 msgid "Default" msgstr "" @@ -3895,7 +3879,7 @@ msgid "This connection is not active." msgstr "" #: plinth/modules/networks/templates/connection_show.html:259 -#: plinth/modules/security/__init__.py:42 +#: plinth/modules/security/__init__.py:34 msgid "Security" msgstr "" @@ -4431,7 +4415,7 @@ msgstr "" msgid "Failed to delete connection: Connection not found." msgstr "" -#: plinth/modules/openvpn/__init__.py:25 +#: plinth/modules/openvpn/__init__.py:20 #, python-brace-format msgid "" "Virtual Private Network (VPN) is a technique for securely connecting two " @@ -4442,20 +4426,20 @@ msgid "" "security and anonymity." msgstr "" -#: plinth/modules/openvpn/__init__.py:53 +#: plinth/modules/openvpn/__init__.py:43 msgid "Connect to VPN services" msgstr "" -#: plinth/modules/openvpn/__init__.py:56 plinth/modules/openvpn/manifest.py:17 +#: plinth/modules/openvpn/__init__.py:46 plinth/modules/openvpn/manifest.py:17 msgid "OpenVPN" msgstr "" -#: plinth/modules/openvpn/__init__.py:57 +#: plinth/modules/openvpn/__init__.py:47 #: plinth/modules/wireguard/__init__.py:49 msgid "Virtual Private Network" msgstr "" -#: plinth/modules/openvpn/__init__.py:68 +#: plinth/modules/openvpn/__init__.py:58 #, python-brace-format msgid "" "Download Profile" @@ -4465,61 +4449,29 @@ msgstr "" msgid "Tunnelblick" msgstr "" -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:7 -msgid "Migrate to ECC" -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:10 -msgid "" -"Your OpenVPN installation is currently using RSA. Switching to the modern " -"Elliptic Curve Cryptography improves speed of establishing a connection and " -"security. This operation is irreversible. It should only take a few minutes " -"on most single board computers." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:19 -#, python-format -msgid "" -"All new installations of OpenVPN on %(box_name)s will use ECC by default. We " -"recommend migrating as soon as possible." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:26 -#, python-format -msgid "" -"Warning: Existing client profiles will be invalidated by this " -"operation. All OpenVPN users on %(box_name)s must download their new " -"profiles. OpenVPN clients compatible with ECC should be used to connect to " -"this server." -msgstr "" - -#: plinth/modules/openvpn/templates/migrate_to_ecc.html:38 -msgid "Migrate" -msgstr "" - -#: plinth/modules/openvpn/templates/openvpn.html:22 +#: plinth/modules/openvpn/templates/openvpn.html:12 msgid "Profile" msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:25 +#: plinth/modules/openvpn/templates/openvpn.html:15 #, python-format msgid "" "To connect to %(box_name)s's VPN, you need to download a profile and feed it " -"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " -"available for most platforms. Click \"Learn more...\" above for recommended " +"to an OpenVPN client on your mobile or desktop machine. OpenVPN Clients are " +"available for most platforms. Click \"Learn more...\" above for recommended " "clients and instructions on how to configure them." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:35 +#: plinth/modules/openvpn/templates/openvpn.html:24 #, python-format -msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." +msgid "Profile is specific to each user of %(box_name)s. Keep it a secret." msgstr "" -#: plinth/modules/openvpn/templates/openvpn.html:46 +#: plinth/modules/openvpn/templates/openvpn.html:34 msgid "Download my profile" msgstr "" -#: plinth/modules/pagekite/__init__.py:21 +#: plinth/modules/pagekite/__init__.py:19 #, python-brace-format msgid "" "PageKite is a system for exposing {box_name} services when you don't have a " @@ -4528,33 +4480,33 @@ msgid "" "following situations:" msgstr "" -#: plinth/modules/pagekite/__init__.py:26 +#: plinth/modules/pagekite/__init__.py:24 #, python-brace-format msgid "{box_name} is behind a restricted firewall." msgstr "" -#: plinth/modules/pagekite/__init__.py:29 +#: plinth/modules/pagekite/__init__.py:27 #, python-brace-format msgid "{box_name} is connected to a (wireless) router which you don't control." msgstr "" -#: plinth/modules/pagekite/__init__.py:31 +#: plinth/modules/pagekite/__init__.py:29 msgid "" "Your ISP does not provide you an external IP address and instead provides " "Internet connection through NAT." msgstr "" -#: plinth/modules/pagekite/__init__.py:33 +#: plinth/modules/pagekite/__init__.py:31 msgid "" "Your ISP does not provide you a static IP address and your IP address " "changes every time you connect to Internet." msgstr "" -#: plinth/modules/pagekite/__init__.py:35 +#: plinth/modules/pagekite/__init__.py:33 msgid "Your ISP limits incoming connections." msgstr "" -#: plinth/modules/pagekite/__init__.py:37 +#: plinth/modules/pagekite/__init__.py:35 #, python-brace-format msgid "" "PageKite works around NAT, firewalls and IP address limitations by using a " @@ -4563,87 +4515,87 @@ msgid "" "the future it might be possible to use your buddy's {box_name} for this." msgstr "" -#: plinth/modules/pagekite/__init__.py:61 +#: plinth/modules/pagekite/__init__.py:59 msgid "PageKite" msgstr "" -#: plinth/modules/pagekite/__init__.py:62 +#: plinth/modules/pagekite/__init__.py:60 msgid "Public Visibility" msgstr "" -#: plinth/modules/pagekite/__init__.py:75 +#: plinth/modules/pagekite/__init__.py:73 msgid "PageKite Domain" msgstr "" -#: plinth/modules/pagekite/forms.py:32 +#: plinth/modules/pagekite/forms.py:30 msgid "Server domain" msgstr "" -#: plinth/modules/pagekite/forms.py:34 +#: plinth/modules/pagekite/forms.py:32 msgid "" "Select your pagekite server. Set \"pagekite.net\" to use the default " "pagekite.net server." msgstr "" -#: plinth/modules/pagekite/forms.py:37 plinth/modules/shadowsocks/forms.py:40 +#: plinth/modules/pagekite/forms.py:35 plinth/modules/shadowsocks/forms.py:39 msgid "Server port" msgstr "" -#: plinth/modules/pagekite/forms.py:38 +#: plinth/modules/pagekite/forms.py:36 msgid "Port of your pagekite server (default: 80)" msgstr "" -#: plinth/modules/pagekite/forms.py:40 +#: plinth/modules/pagekite/forms.py:38 msgid "Kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:41 +#: plinth/modules/pagekite/forms.py:39 msgid "Example: mybox.pagekite.me" msgstr "" -#: plinth/modules/pagekite/forms.py:43 +#: plinth/modules/pagekite/forms.py:41 msgid "Invalid kite name" msgstr "" -#: plinth/modules/pagekite/forms.py:47 +#: plinth/modules/pagekite/forms.py:45 msgid "Kite secret" msgstr "" -#: plinth/modules/pagekite/forms.py:48 +#: plinth/modules/pagekite/forms.py:46 msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -#: plinth/modules/pagekite/forms.py:88 +#: plinth/modules/pagekite/forms.py:85 msgid "protocol" msgstr "" -#: plinth/modules/pagekite/forms.py:91 +#: plinth/modules/pagekite/forms.py:88 msgid "external (frontend) port" msgstr "" -#: plinth/modules/pagekite/forms.py:94 +#: plinth/modules/pagekite/forms.py:91 msgid "internal (freedombox) port" msgstr "" -#: plinth/modules/pagekite/forms.py:95 +#: plinth/modules/pagekite/forms.py:92 msgid "Enable Subdomains" msgstr "" -#: plinth/modules/pagekite/forms.py:130 +#: plinth/modules/pagekite/forms.py:127 msgid "Deleted custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:164 +#: plinth/modules/pagekite/forms.py:161 msgid "This service is already available as a standard service." msgstr "" -#: plinth/modules/pagekite/forms.py:172 +#: plinth/modules/pagekite/forms.py:169 msgid "Added custom service" msgstr "" -#: plinth/modules/pagekite/forms.py:175 +#: plinth/modules/pagekite/forms.py:172 msgid "This service already exists" msgstr "" @@ -4677,29 +4629,29 @@ msgid "" "HTTPS on ports other than 443 is known to cause problems." msgstr "" -#: plinth/modules/pagekite/utils.py:46 +#: plinth/modules/pagekite/utils.py:45 msgid "Web Server (HTTP)" msgstr "" -#: plinth/modules/pagekite/utils.py:48 +#: plinth/modules/pagekite/utils.py:47 #, python-brace-format msgid "Site will be available at http://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:60 +#: plinth/modules/pagekite/utils.py:59 msgid "Web Server (HTTPS)" msgstr "" -#: plinth/modules/pagekite/utils.py:62 +#: plinth/modules/pagekite/utils.py:61 #, python-brace-format msgid "Site will be available at https://{0}" msgstr "" -#: plinth/modules/pagekite/utils.py:74 +#: plinth/modules/pagekite/utils.py:73 msgid "Secure Shell (SSH)" msgstr "" -#: plinth/modules/pagekite/utils.py:76 +#: plinth/modules/pagekite/utils.py:75 msgid "" "See SSH client setup instructions" @@ -4741,8 +4693,8 @@ msgid "" "finished before shutting down or restarting." msgstr "" -#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:171 -#: plinth/templates/base.html:172 +#: plinth/modules/power/templates/power.html:22 plinth/templates/base.html:174 +#: plinth/templates/base.html:175 msgid "Restart" msgstr "" @@ -4784,6 +4736,37 @@ msgstr "" msgid "Shut Down Now" msgstr "" +#: plinth/modules/privacy/__init__.py:15 +msgid "Manage system-wide privacy settings." +msgstr "" + +#: plinth/modules/privacy/__init__.py:32 plinth/modules/privacy/__init__.py:64 +msgid "Privacy" +msgstr "" + +#: plinth/modules/privacy/__init__.py:62 +msgid "Please update privacy settings to match your preferences." +msgstr "" + +#: plinth/modules/privacy/__init__.py:67 +msgid "Review privacy setting" +msgstr "" + +#: plinth/modules/privacy/forms.py:15 +msgid "Periodically submit a list of apps used (suggested)" +msgstr "" + +#: plinth/modules/privacy/forms.py:17 +#, python-brace-format +msgid "" +"Help Debian/{box_name} developers by participating in the Popularity Contest " +"package survey program. When enabled, a list of apps used on this system " +"will be anonymously submitted to Debian every week. Statistics for the data " +"collected are publicly available at popcon.debian.org. Submission happens over the Tor " +"network for additional anonymity if Tor app is enabled." +msgstr "" + #: plinth/modules/privoxy/__init__.py:23 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " @@ -4815,7 +4798,7 @@ msgstr "" msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" -#: plinth/modules/quassel/__init__.py:27 +#: plinth/modules/quassel/__init__.py:24 #, python-brace-format msgid "" "Quassel is an IRC application that is split into two parts, a \"core\" and a " @@ -4826,7 +4809,7 @@ msgid "" "connect and disconnect from it." msgstr "" -#: plinth/modules/quassel/__init__.py:34 +#: plinth/modules/quassel/__init__.py:31 msgid "" "You can connect to your Quassel core on the default Quassel port 4242. " "Clients to connect to Quassel from your mobile devices are available." msgstr "" -#: plinth/modules/quassel/__init__.py:54 plinth/modules/quassel/manifest.py:9 +#: plinth/modules/quassel/__init__.py:51 plinth/modules/quassel/manifest.py:9 msgid "Quassel" msgstr "" -#: plinth/modules/quassel/__init__.py:55 +#: plinth/modules/quassel/__init__.py:52 msgid "IRC Client" msgstr "" @@ -4846,7 +4829,7 @@ msgstr "" msgid "Quasseldroid" msgstr "" -#: plinth/modules/radicale/__init__.py:25 +#: plinth/modules/radicale/__init__.py:24 #, python-brace-format msgid "" "Radicale is a CalDAV and CardDAV server. It allows synchronization and " @@ -4856,19 +4839,19 @@ msgid "" "{box_name} login." msgstr "" -#: plinth/modules/radicale/__init__.py:31 +#: plinth/modules/radicale/__init__.py:30 msgid "" "Radicale provides a basic web interface, which only supports creating new " "calendars and addressbooks. It does not support adding events or contacts, " "which must be done using a separate client." msgstr "" -#: plinth/modules/radicale/__init__.py:53 +#: plinth/modules/radicale/__init__.py:52 #: plinth/modules/radicale/manifest.py:74 msgid "Radicale" msgstr "" -#: plinth/modules/radicale/__init__.py:54 +#: plinth/modules/radicale/__init__.py:53 msgid "Calendar and Addressbook" msgstr "" @@ -4927,7 +4910,7 @@ msgid "" "existing calendars and address books." msgstr "" -#: plinth/modules/radicale/views.py:35 +#: plinth/modules/radicale/views.py:32 msgid "Access rights configuration updated" msgstr "" @@ -4999,7 +4982,7 @@ msgid "" "your {box_name} credentials." msgstr "" -#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:48 +#: plinth/modules/rssbridge/__init__.py:45 plinth/modules/ttrss/__init__.py:45 msgid "Read and subscribe to news feeds" msgstr "" @@ -5012,13 +4995,13 @@ msgstr "" msgid "RSS Feed Generator" msgstr "" -#: plinth/modules/samba/__init__.py:27 +#: plinth/modules/samba/__init__.py:23 msgid "" "Samba allows to share files and folders between FreedomBox and other " "computers in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:30 +#: plinth/modules/samba/__init__.py:26 #, python-brace-format msgid "" "After installation, you can choose which disks to use for sharing. Enabled " @@ -5027,31 +5010,31 @@ msgid "" "There are three types of shares you can choose from: " msgstr "" -#: plinth/modules/samba/__init__.py:35 +#: plinth/modules/samba/__init__.py:31 msgid "Open share - accessible to everyone in your local network." msgstr "" -#: plinth/modules/samba/__init__.py:36 +#: plinth/modules/samba/__init__.py:32 msgid "" "Group share - accessible only to FreedomBox users who are in the freedombox-" "share group." msgstr "" -#: plinth/modules/samba/__init__.py:38 +#: plinth/modules/samba/__init__.py:34 msgid "" "Home share - every user in the freedombox-share group can have their own " "private space." msgstr "" -#: plinth/modules/samba/__init__.py:54 +#: plinth/modules/samba/__init__.py:50 msgid "Access to the private shares" msgstr "" -#: plinth/modules/samba/__init__.py:57 +#: plinth/modules/samba/__init__.py:53 msgid "Samba" msgstr "" -#: plinth/modules/samba/__init__.py:58 +#: plinth/modules/samba/__init__.py:54 msgid "Network File Storage" msgstr "" @@ -5129,15 +5112,15 @@ msgstr "" msgid "Action" msgstr "" -#: plinth/modules/samba/views.py:34 +#: plinth/modules/samba/views.py:33 msgid "FreedomBox OS disk" msgstr "" -#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:146 +#: plinth/modules/samba/views.py:60 plinth/modules/storage/forms.py:140 msgid "Open Share" msgstr "" -#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:144 +#: plinth/modules/samba/views.py:64 plinth/modules/storage/forms.py:138 msgid "Group Share" msgstr "" @@ -5163,51 +5146,51 @@ msgstr "" msgid "Error disabling share: {error_message}" msgstr "" -#: plinth/modules/searx/__init__.py:22 +#: plinth/modules/searx/__init__.py:19 msgid "" "Searx is a privacy-respecting Internet metasearch engine. It aggregrates and " "displays results from multiple search engines." msgstr "" -#: plinth/modules/searx/__init__.py:24 +#: plinth/modules/searx/__init__.py:21 msgid "" "Searx can be used to avoid tracking and profiling by search engines. It " "stores no cookies by default." msgstr "" -#: plinth/modules/searx/__init__.py:40 +#: plinth/modules/searx/__init__.py:37 msgid "Search the web" msgstr "" -#: plinth/modules/searx/__init__.py:43 plinth/modules/searx/manifest.py:6 +#: plinth/modules/searx/__init__.py:40 plinth/modules/searx/manifest.py:6 msgid "Searx" msgstr "" -#: plinth/modules/searx/__init__.py:44 +#: plinth/modules/searx/__init__.py:41 msgid "Web Search" msgstr "" -#: plinth/modules/searx/forms.py:13 +#: plinth/modules/searx/forms.py:12 msgid "Safe Search" msgstr "" -#: plinth/modules/searx/forms.py:14 +#: plinth/modules/searx/forms.py:13 msgid "Select the default family filter to apply to your search results." msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Moderate" msgstr "" -#: plinth/modules/searx/forms.py:15 +#: plinth/modules/searx/forms.py:14 msgid "Strict" msgstr "" -#: plinth/modules/searx/forms.py:18 +#: plinth/modules/searx/forms.py:17 msgid "Allow Public Access" msgstr "" -#: plinth/modules/searx/forms.py:19 +#: plinth/modules/searx/forms.py:18 msgid "Allow this application to be used by anyone who can reach it." msgstr "" @@ -5360,14 +5343,14 @@ msgstr "" msgid "Shaarlier" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:21 +#: plinth/modules/shadowsocks/__init__.py:18 msgid "" "Shadowsocks is a lightweight and secure SOCKS5 proxy, designed to protect " "your Internet traffic. It can be used to bypass Internet filtering and " "censorship." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:25 +#: plinth/modules/shadowsocks/__init__.py:22 #, python-brace-format msgid "" "Your {box_name} can run a Shadowsocks client, that can connect to a " @@ -5376,97 +5359,97 @@ msgid "" "the Shadowsocks server." msgstr "" -#: plinth/modules/shadowsocks/__init__.py:30 +#: plinth/modules/shadowsocks/__init__.py:27 msgid "" "To use Shadowsocks after setup, set the SOCKS5 proxy URL in your device, " "browser or application to http://freedombox_address:1080/" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:49 +#: plinth/modules/shadowsocks/__init__.py:46 msgid "Shadowsocks" msgstr "" -#: plinth/modules/shadowsocks/__init__.py:51 +#: plinth/modules/shadowsocks/__init__.py:48 msgid "Socks5 Proxy" msgstr "" -#: plinth/modules/shadowsocks/forms.py:12 -#: plinth/modules/shadowsocks/forms.py:13 +#: plinth/modules/shadowsocks/forms.py:10 +#: plinth/modules/shadowsocks/forms.py:11 msgid "Recommended" msgstr "" -#: plinth/modules/shadowsocks/forms.py:37 +#: plinth/modules/shadowsocks/forms.py:36 msgid "Server" msgstr "" -#: plinth/modules/shadowsocks/forms.py:38 +#: plinth/modules/shadowsocks/forms.py:37 msgid "Server hostname or IP address" msgstr "" -#: plinth/modules/shadowsocks/forms.py:42 +#: plinth/modules/shadowsocks/forms.py:41 msgid "Server port number" msgstr "" -#: plinth/modules/shadowsocks/forms.py:45 +#: plinth/modules/shadowsocks/forms.py:44 msgid "Password used to encrypt data. Must match server password." msgstr "" -#: plinth/modules/shadowsocks/forms.py:50 +#: plinth/modules/shadowsocks/forms.py:49 msgid "Encryption method. Must match setting on server." msgstr "" -#: plinth/modules/sharing/__init__.py:21 +#: plinth/modules/sharing/__init__.py:16 #, python-brace-format msgid "" "Sharing allows you to share files and folders on your {box_name} over the " "web with chosen groups of users." msgstr "" -#: plinth/modules/sharing/__init__.py:38 +#: plinth/modules/sharing/__init__.py:33 msgid "Sharing" msgstr "" -#: plinth/modules/sharing/forms.py:18 +#: plinth/modules/sharing/forms.py:17 msgid "Name of the share" msgstr "" -#: plinth/modules/sharing/forms.py:20 +#: plinth/modules/sharing/forms.py:19 msgid "" "A lowercase alpha-numeric string that uniquely identifies a share. Example: " "media." msgstr "" -#: plinth/modules/sharing/forms.py:24 +#: plinth/modules/sharing/forms.py:23 msgid "Path to share" msgstr "" -#: plinth/modules/sharing/forms.py:25 +#: plinth/modules/sharing/forms.py:24 msgid "Disk path to a folder on this server that you intend to share." msgstr "" -#: plinth/modules/sharing/forms.py:28 +#: plinth/modules/sharing/forms.py:27 msgid "Public share" msgstr "" -#: plinth/modules/sharing/forms.py:29 +#: plinth/modules/sharing/forms.py:28 msgid "Make files in this folder available to anyone with the link." msgstr "" -#: plinth/modules/sharing/forms.py:34 +#: plinth/modules/sharing/forms.py:33 msgid "User groups that can read the files in the share:" msgstr "" -#: plinth/modules/sharing/forms.py:36 +#: plinth/modules/sharing/forms.py:35 msgid "" "Users of the selected user groups will be able to read the files in the " "share." msgstr "" -#: plinth/modules/sharing/forms.py:52 +#: plinth/modules/sharing/forms.py:51 msgid "A share with this name already exists." msgstr "" -#: plinth/modules/sharing/forms.py:63 +#: plinth/modules/sharing/forms.py:62 msgid "Shares should be either public or shared with at least one group" msgstr "" @@ -5503,26 +5486,26 @@ msgstr "" msgid "Add Share" msgstr "" -#: plinth/modules/sharing/views.py:59 +#: plinth/modules/sharing/views.py:60 msgid "Share edited." msgstr "" -#: plinth/modules/sharing/views.py:64 +#: plinth/modules/sharing/views.py:65 msgid "Edit Share" msgstr "" -#: plinth/modules/sharing/views.py:95 +#: plinth/modules/sharing/views.py:96 msgid "Share deleted." msgstr "" -#: plinth/modules/snapshot/__init__.py:22 +#: plinth/modules/snapshot/__init__.py:18 msgid "" "Snapshots allows creating and managing btrfs file system snapshots. These " "can be used to roll back the system to a previously known good state in case " "of unwanted changes to the system." msgstr "" -#: plinth/modules/snapshot/__init__.py:26 +#: plinth/modules/snapshot/__init__.py:22 #, no-python-format msgid "" "Snapshots are taken periodically (called timeline snapshots) and also before " @@ -5530,14 +5513,14 @@ msgid "" "cleaned up according to the settings below." msgstr "" -#: plinth/modules/snapshot/__init__.py:29 +#: plinth/modules/snapshot/__init__.py:25 msgid "" "Snapshots currently work on btrfs file systems only and on the root " "partition only. Snapshots are not a replacement for backups since they can only be stored on the same partition. " msgstr "" -#: plinth/modules/snapshot/__init__.py:54 +#: plinth/modules/snapshot/__init__.py:50 msgid "Storage Snapshots" msgstr "" @@ -5631,7 +5614,7 @@ msgstr "" #: plinth/modules/snapshot/templates/snapshot_delete_selected.html:42 #: plinth/modules/snapshot/templates/snapshot_manage.html:20 -#: plinth/modules/snapshot/views.py:203 +#: plinth/modules/snapshot/views.py:194 msgid "Delete Snapshots" msgstr "" @@ -5679,57 +5662,57 @@ msgstr "" msgid "Rollback to Snapshot #%(number)s" msgstr "" -#: plinth/modules/snapshot/views.py:29 +#: plinth/modules/snapshot/views.py:24 msgid "manually created" msgstr "" -#: plinth/modules/snapshot/views.py:30 +#: plinth/modules/snapshot/views.py:25 msgid "timeline" msgstr "" -#: plinth/modules/snapshot/views.py:31 +#: plinth/modules/snapshot/views.py:26 msgid "apt" msgstr "" -#: plinth/modules/snapshot/views.py:41 +#: plinth/modules/snapshot/views.py:36 msgid "Manage Snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:94 +#: plinth/modules/snapshot/views.py:89 msgid "Created snapshot." msgstr "" -#: plinth/modules/snapshot/views.py:158 +#: plinth/modules/snapshot/views.py:151 msgid "Storage snapshots configuration updated" msgstr "" -#: plinth/modules/snapshot/views.py:162 +#: plinth/modules/snapshot/views.py:155 #, python-brace-format msgid "Action error: {0} [{1}] [{2}]" msgstr "" -#: plinth/modules/snapshot/views.py:190 +#: plinth/modules/snapshot/views.py:181 msgid "Deleted selected snapshots" msgstr "" -#: plinth/modules/snapshot/views.py:195 +#: plinth/modules/snapshot/views.py:186 msgid "Snapshot is currently in use. Please try again later." msgstr "" -#: plinth/modules/snapshot/views.py:214 +#: plinth/modules/snapshot/views.py:205 #, python-brace-format msgid "Rolled back to snapshot #{number}." msgstr "" -#: plinth/modules/snapshot/views.py:217 +#: plinth/modules/snapshot/views.py:208 msgid "The system must be restarted to complete the rollback." msgstr "" -#: plinth/modules/snapshot/views.py:229 +#: plinth/modules/snapshot/views.py:218 msgid "Rollback to Snapshot" msgstr "" -#: plinth/modules/ssh/__init__.py:23 +#: plinth/modules/ssh/__init__.py:20 msgid "" "A Secure Shell server uses the secure shell protocol to accept connections " "from remote computers. An authorized remote computer can perform " @@ -5737,7 +5720,7 @@ msgid "" "connections." msgstr "" -#: plinth/modules/ssh/__init__.py:43 +#: plinth/modules/ssh/__init__.py:40 msgid "Secure Shell (SSH) Server" msgstr "" @@ -5770,14 +5753,6 @@ msgstr "" msgid "Fingerprint" msgstr "" -#: plinth/modules/ssh/views.py:48 -msgid "SSH authentication with password disabled." -msgstr "" - -#: plinth/modules/ssh/views.py:51 -msgid "SSH authentication with password enabled." -msgstr "" - #: plinth/modules/sso/__init__.py:26 msgid "Single Sign On" msgstr "" @@ -5790,7 +5765,7 @@ msgstr "" msgid "Logged out successfully." msgstr "" -#: plinth/modules/storage/__init__.py:26 +#: plinth/modules/storage/__init__.py:22 #, python-brace-format msgid "" "This module allows you to manage storage media attached to your {box_name}. " @@ -5798,143 +5773,143 @@ msgid "" "media, expand the root partition etc." msgstr "" -#: plinth/modules/storage/__init__.py:49 plinth/modules/storage/__init__.py:319 -#: plinth/modules/storage/__init__.py:350 +#: plinth/modules/storage/__init__.py:45 plinth/modules/storage/__init__.py:306 +#: plinth/modules/storage/__init__.py:337 msgid "Storage" msgstr "" -#: plinth/modules/storage/__init__.py:227 +#: plinth/modules/storage/__init__.py:214 #, python-brace-format msgid "{disk_size:.1f} bytes" msgstr "" -#: plinth/modules/storage/__init__.py:231 +#: plinth/modules/storage/__init__.py:218 #, python-brace-format msgid "{disk_size:.1f} KiB" msgstr "" -#: plinth/modules/storage/__init__.py:235 +#: plinth/modules/storage/__init__.py:222 #, python-brace-format msgid "{disk_size:.1f} MiB" msgstr "" -#: plinth/modules/storage/__init__.py:239 +#: plinth/modules/storage/__init__.py:226 #, python-brace-format msgid "{disk_size:.1f} GiB" msgstr "" -#: plinth/modules/storage/__init__.py:242 +#: plinth/modules/storage/__init__.py:229 #, python-brace-format msgid "{disk_size:.1f} TiB" msgstr "" -#: plinth/modules/storage/__init__.py:254 +#: plinth/modules/storage/__init__.py:241 msgid "The operation failed." msgstr "" -#: plinth/modules/storage/__init__.py:256 +#: plinth/modules/storage/__init__.py:243 msgid "The operation was cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:258 +#: plinth/modules/storage/__init__.py:245 msgid "The device is already unmounting." msgstr "" -#: plinth/modules/storage/__init__.py:260 +#: plinth/modules/storage/__init__.py:247 msgid "The operation is not supported due to missing driver/tool support." msgstr "" -#: plinth/modules/storage/__init__.py:263 +#: plinth/modules/storage/__init__.py:250 msgid "The operation timed out." msgstr "" -#: plinth/modules/storage/__init__.py:265 +#: plinth/modules/storage/__init__.py:252 msgid "The operation would wake up a disk that is in a deep-sleep state." msgstr "" -#: plinth/modules/storage/__init__.py:268 +#: plinth/modules/storage/__init__.py:255 msgid "Attempting to unmount a device that is busy." msgstr "" -#: plinth/modules/storage/__init__.py:270 +#: plinth/modules/storage/__init__.py:257 msgid "The operation has already been cancelled." msgstr "" -#: plinth/modules/storage/__init__.py:272 -#: plinth/modules/storage/__init__.py:274 -#: plinth/modules/storage/__init__.py:276 +#: plinth/modules/storage/__init__.py:259 +#: plinth/modules/storage/__init__.py:261 +#: plinth/modules/storage/__init__.py:263 msgid "Not authorized to perform the requested operation." msgstr "" -#: plinth/modules/storage/__init__.py:278 +#: plinth/modules/storage/__init__.py:265 msgid "The device is already mounted." msgstr "" -#: plinth/modules/storage/__init__.py:280 +#: plinth/modules/storage/__init__.py:267 msgid "The device is not mounted." msgstr "" -#: plinth/modules/storage/__init__.py:282 +#: plinth/modules/storage/__init__.py:269 msgid "Not permitted to use the requested option." msgstr "" -#: plinth/modules/storage/__init__.py:284 +#: plinth/modules/storage/__init__.py:271 msgid "The device is mounted by another user." msgstr "" -#: plinth/modules/storage/__init__.py:314 +#: plinth/modules/storage/__init__.py:301 #, no-python-format, python-brace-format msgid "Low space on system partition: {percent_used}% used, {free_space} free." msgstr "" -#: plinth/modules/storage/__init__.py:316 +#: plinth/modules/storage/__init__.py:303 msgid "Low disk space" msgstr "" -#: plinth/modules/storage/__init__.py:344 +#: plinth/modules/storage/__init__.py:331 msgid "Disk failure imminent" msgstr "" -#: plinth/modules/storage/__init__.py:346 +#: plinth/modules/storage/__init__.py:333 #, python-brace-format msgid "" "Disk {id} is reporting that it is likely to fail in the near future. Copy " "any data while you still can and replace the drive." msgstr "" -#: plinth/modules/storage/forms.py:62 +#: plinth/modules/storage/forms.py:63 msgid "Invalid directory name." msgstr "" -#: plinth/modules/storage/forms.py:79 +#: plinth/modules/storage/forms.py:73 msgid "Directory does not exist." msgstr "" -#: plinth/modules/storage/forms.py:82 +#: plinth/modules/storage/forms.py:75 msgid "Path is not a directory." msgstr "" -#: plinth/modules/storage/forms.py:85 +#: plinth/modules/storage/forms.py:79 msgid "Directory is not readable by the user." msgstr "" -#: plinth/modules/storage/forms.py:88 +#: plinth/modules/storage/forms.py:82 msgid "Directory is not writable by the user." msgstr "" -#: plinth/modules/storage/forms.py:93 +#: plinth/modules/storage/forms.py:87 msgid "Directory" msgstr "" -#: plinth/modules/storage/forms.py:95 +#: plinth/modules/storage/forms.py:89 msgid "Subdirectory (optional)" msgstr "" -#: plinth/modules/storage/forms.py:142 +#: plinth/modules/storage/forms.py:136 msgid "Share" msgstr "" -#: plinth/modules/storage/forms.py:150 +#: plinth/modules/storage/forms.py:144 msgid "Other directory (specify below)" msgstr "" @@ -5968,7 +5943,7 @@ msgstr "" #: plinth/modules/storage/templates/storage.html:89 #: plinth/modules/storage/templates/storage_expand.html:24 -#: plinth/modules/storage/views.py:58 +#: plinth/modules/storage/views.py:55 msgid "Expand Root Partition" msgstr "" @@ -5986,30 +5961,30 @@ msgid "" "root partition." msgstr "" -#: plinth/modules/storage/views.py:70 +#: plinth/modules/storage/views.py:67 #, python-brace-format msgid "Error expanding partition: {exception}" msgstr "" -#: plinth/modules/storage/views.py:73 +#: plinth/modules/storage/views.py:70 msgid "Partition expanded successfully." msgstr "" -#: plinth/modules/storage/views.py:91 +#: plinth/modules/storage/views.py:87 #, python-brace-format msgid "{drive_vendor} {drive_model} can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:95 +#: plinth/modules/storage/views.py:91 msgid "Device can be safely unplugged." msgstr "" -#: plinth/modules/storage/views.py:102 +#: plinth/modules/storage/views.py:98 #, python-brace-format msgid "Error ejecting device: {error_message}" msgstr "" -#: plinth/modules/syncthing/__init__.py:23 +#: plinth/modules/syncthing/__init__.py:21 msgid "" "Syncthing is an application to synchronize files across multiple devices, e." "g. your desktop computer and mobile phone. Creation, modification, or " @@ -6017,7 +5992,7 @@ msgid "" "other devices that also run Syncthing." msgstr "" -#: plinth/modules/syncthing/__init__.py:28 +#: plinth/modules/syncthing/__init__.py:26 #, python-brace-format msgid "" "Running Syncthing on {box_name} provides an extra synchronization point for " @@ -6029,20 +6004,20 @@ msgid "" "\"syncthing-access\" group." msgstr "" -#: plinth/modules/syncthing/__init__.py:55 +#: plinth/modules/syncthing/__init__.py:53 msgid "Administer Syncthing application" msgstr "" -#: plinth/modules/syncthing/__init__.py:59 +#: plinth/modules/syncthing/__init__.py:57 #: plinth/modules/syncthing/manifest.py:12 msgid "Syncthing" msgstr "" -#: plinth/modules/syncthing/__init__.py:60 +#: plinth/modules/syncthing/__init__.py:58 msgid "File Synchronization" msgstr "" -#: plinth/modules/tor/__init__.py:27 +#: plinth/modules/tor/__init__.py:23 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6051,47 +6026,47 @@ msgid "" "\">Tor Browser." msgstr "" -#: plinth/modules/tor/__init__.py:34 +#: plinth/modules/tor/__init__.py:30 #, python-brace-format msgid "" "A Tor SOCKS port is available on your {box_name} for internal networks on " "TCP port 9050." msgstr "" -#: plinth/modules/tor/__init__.py:52 +#: plinth/modules/tor/__init__.py:48 msgid "Tor" msgstr "" -#: plinth/modules/tor/__init__.py:69 +#: plinth/modules/tor/__init__.py:65 msgid "Tor Onion Service" msgstr "" -#: plinth/modules/tor/__init__.py:73 +#: plinth/modules/tor/__init__.py:69 msgid "Tor Socks Proxy" msgstr "" -#: plinth/modules/tor/__init__.py:77 +#: plinth/modules/tor/__init__.py:73 msgid "Tor Bridge Relay" msgstr "" -#: plinth/modules/tor/__init__.py:132 +#: plinth/modules/tor/__init__.py:127 msgid "Tor relay port available" msgstr "" -#: plinth/modules/tor/__init__.py:142 +#: plinth/modules/tor/__init__.py:137 msgid "Obfs3 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:152 +#: plinth/modules/tor/__init__.py:147 msgid "Obfs4 transport registered" msgstr "" -#: plinth/modules/tor/__init__.py:220 +#: plinth/modules/tor/__init__.py:212 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: plinth/modules/tor/__init__.py:231 +#: plinth/modules/tor/__init__.py:223 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6189,13 +6164,13 @@ msgstr "" msgid "Ports" msgstr "" -#: plinth/modules/tor/views.py:55 +#: plinth/modules/tor/views.py:53 #, fuzzy #| msgid "An error occurred during configuration." msgid "Updating configuration" msgstr "設置過程中發生錯誤。" -#: plinth/modules/tor/views.py:72 +#: plinth/modules/tor/views.py:70 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error configuring app: {error}" @@ -6253,14 +6228,14 @@ msgstr "" msgid "Transmission" msgstr "" -#: plinth/modules/ttrss/__init__.py:23 +#: plinth/modules/ttrss/__init__.py:20 msgid "" "Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to " "allow reading news from any location, while feeling as close to a real " "desktop application as possible." msgstr "" -#: plinth/modules/ttrss/__init__.py:27 +#: plinth/modules/ttrss/__init__.py:24 #, fuzzy, python-brace-format #| msgid "" #| "It can be accessed by any user on {box_name} " @@ -6272,17 +6247,17 @@ msgstr "" "它可以由 {box_name} 上屬於 admin 群組的 任何使用者存取。" -#: plinth/modules/ttrss/__init__.py:32 +#: plinth/modules/ttrss/__init__.py:29 msgid "" "When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting." msgstr "" -#: plinth/modules/ttrss/__init__.py:51 plinth/modules/ttrss/manifest.py:18 +#: plinth/modules/ttrss/__init__.py:48 plinth/modules/ttrss/manifest.py:18 msgid "Tiny Tiny RSS" msgstr "" -#: plinth/modules/ttrss/__init__.py:52 +#: plinth/modules/ttrss/__init__.py:49 msgid "News Feed Reader" msgstr "" @@ -6290,12 +6265,12 @@ msgstr "" msgid "Tiny Tiny RSS (Fork)" msgstr "" -#: plinth/modules/upgrades/__init__.py:39 +#: plinth/modules/upgrades/__init__.py:35 #: plinth/modules/upgrades/templates/update-firstboot.html:14 msgid "Check for and apply the latest software and security updates." msgstr "" -#: plinth/modules/upgrades/__init__.py:40 +#: plinth/modules/upgrades/__init__.py:36 msgid "" "Updates are run at 06:00 everyday according to local time zone. Set your " "time zone in Date & Time app. Apps are restarted after update causing them " @@ -6303,33 +6278,33 @@ msgid "" "automatically at 02:00 causing all apps to be unavailable briefly." msgstr "" -#: plinth/modules/upgrades/__init__.py:72 -#: plinth/modules/upgrades/__init__.py:127 +#: plinth/modules/upgrades/__init__.py:64 +#: plinth/modules/upgrades/__init__.py:119 #: plinth/modules/upgrades/templates/update-firstboot-progress.html:11 #: plinth/modules/upgrades/templates/update-firstboot.html:11 msgid "Software Update" msgstr "" -#: plinth/modules/upgrades/__init__.py:130 +#: plinth/modules/upgrades/__init__.py:122 msgid "FreedomBox Updated" msgstr "" -#: plinth/modules/upgrades/__init__.py:222 +#: plinth/modules/upgrades/__init__.py:190 msgid "Could not start distribution update" msgstr "" -#: plinth/modules/upgrades/__init__.py:224 +#: plinth/modules/upgrades/__init__.py:192 msgid "" "There is not enough free space in the root partition to start the " "distribution update. Please ensure at least 5 GB is free. Distribution " "update will be retried after 24 hours, if enabled." msgstr "" -#: plinth/modules/upgrades/__init__.py:235 +#: plinth/modules/upgrades/__init__.py:203 msgid "Distribution update started" msgstr "" -#: plinth/modules/upgrades/__init__.py:237 +#: plinth/modules/upgrades/__init__.py:205 msgid "" "Started update to next stable release. This may take a long time to complete." msgstr "" @@ -6477,51 +6452,51 @@ msgstr "" msgid "Test distribution upgrade now" msgstr "" -#: plinth/modules/upgrades/views.py:68 +#: plinth/modules/upgrades/views.py:71 #, python-brace-format msgid "Error when configuring unattended-upgrades: {error}" msgstr "" -#: plinth/modules/upgrades/views.py:72 +#: plinth/modules/upgrades/views.py:75 msgid "Automatic upgrades enabled" msgstr "" -#: plinth/modules/upgrades/views.py:75 +#: plinth/modules/upgrades/views.py:78 msgid "Automatic upgrades disabled" msgstr "" -#: plinth/modules/upgrades/views.py:83 +#: plinth/modules/upgrades/views.py:86 msgid "Distribution upgrade enabled" msgstr "" -#: plinth/modules/upgrades/views.py:86 +#: plinth/modules/upgrades/views.py:89 msgid "Distribution upgrade disabled" msgstr "" -#: plinth/modules/upgrades/views.py:128 +#: plinth/modules/upgrades/views.py:126 msgid "Upgrade process started." msgstr "" -#: plinth/modules/upgrades/views.py:130 +#: plinth/modules/upgrades/views.py:128 msgid "Starting upgrade failed." msgstr "" -#: plinth/modules/upgrades/views.py:140 +#: plinth/modules/upgrades/views.py:138 msgid "Frequent feature updates activated." msgstr "" -#: plinth/modules/upgrades/views.py:223 +#: plinth/modules/upgrades/views.py:224 msgid "Starting distribution upgrade test." msgstr "" -#: plinth/modules/users/__init__.py:29 +#: plinth/modules/users/__init__.py:28 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: plinth/modules/users/__init__.py:34 +#: plinth/modules/users/__init__.py:33 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6529,15 +6504,15 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: plinth/modules/users/__init__.py:55 +#: plinth/modules/users/__init__.py:54 msgid "Users and Groups" msgstr "" -#: plinth/modules/users/__init__.py:75 +#: plinth/modules/users/__init__.py:74 msgid "Access to all services and system settings" msgstr "" -#: plinth/modules/users/__init__.py:111 +#: plinth/modules/users/__init__.py:110 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" @@ -6555,21 +6530,21 @@ msgid "" "Required. 150 characters or fewer. English letters, digits and @/./-/_ only." msgstr "" -#: plinth/modules/users/forms.py:78 +#: plinth/modules/users/forms.py:79 msgid "Authorization Password" msgstr "" -#: plinth/modules/users/forms.py:84 +#: plinth/modules/users/forms.py:86 #, python-brace-format msgid "" "Enter the password for user \"{user}\" to authorize account modifications." msgstr "" -#: plinth/modules/users/forms.py:93 +#: plinth/modules/users/forms.py:95 msgid "Invalid password." msgstr "" -#: plinth/modules/users/forms.py:110 +#: plinth/modules/users/forms.py:113 msgid "" "Select which services should be available to the new user. The user will be " "able to log in to services that support single sign-on through LDAP, if they " @@ -6578,12 +6553,12 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: plinth/modules/users/forms.py:155 plinth/modules/users/forms.py:399 +#: plinth/modules/users/forms.py:156 plinth/modules/users/forms.py:374 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: plinth/modules/users/forms.py:168 +#: plinth/modules/users/forms.py:167 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" @@ -6599,41 +6574,41 @@ msgid "" "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: plinth/modules/users/forms.py:269 +#: plinth/modules/users/forms.py:265 msgid "Renaming LDAP user failed." msgstr "" -#: plinth/modules/users/forms.py:282 +#: plinth/modules/users/forms.py:276 msgid "Failed to remove user from group." msgstr "" -#: plinth/modules/users/forms.py:294 +#: plinth/modules/users/forms.py:286 msgid "Failed to add user to group." msgstr "" -#: plinth/modules/users/forms.py:307 +#: plinth/modules/users/forms.py:293 msgid "Unable to set SSH keys." msgstr "" -#: plinth/modules/users/forms.py:325 +#: plinth/modules/users/forms.py:306 msgid "Failed to change user status." msgstr "" -#: plinth/modules/users/forms.py:370 +#: plinth/modules/users/forms.py:347 msgid "Changing LDAP user password failed." msgstr "" -#: plinth/modules/users/forms.py:410 +#: plinth/modules/users/forms.py:382 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: plinth/modules/users/forms.py:429 +#: plinth/modules/users/forms.py:401 #, python-brace-format msgid "Failed to restrict console access: {error}" msgstr "" -#: plinth/modules/users/forms.py:442 +#: plinth/modules/users/forms.py:414 msgid "User account created, you are now logged in" msgstr "" @@ -6650,12 +6625,12 @@ msgstr "" #: plinth/modules/users/templates/users_create.html:19 #: plinth/modules/users/templates/users_list.html:15 #: plinth/modules/users/templates/users_list.html:17 -#: plinth/modules/users/views.py:44 +#: plinth/modules/users/views.py:46 msgid "Create User" msgstr "" #: plinth/modules/users/templates/users_delete.html:11 -#: plinth/modules/users/views.py:134 +#: plinth/modules/users/views.py:138 msgid "Delete User" msgstr "" @@ -6693,17 +6668,17 @@ msgid "The following administrator accounts exist in the system." msgstr "" #: plinth/modules/users/templates/users_firstboot.html:50 -#, python-format, python-brace-format +#, python-format msgid "" "Delete these accounts from command line and refresh the page to create an " "account that is usable with %(box_name)s. On the command line run the " -"command 'echo \"{password}\" | /usr/share/plinth/actions/users remove-user " -"{username}'. If an account is already usable with %(box_name)s, skip this " -"step." +"command \"echo '{\"args\": [\"USERNAME\", \"PASSWORD\"], \"kwargs\": {}}' | " +"sudo /usr/share/plinth/actions/actions users remove_user\". If an account is " +"already usable with %(box_name)s, skip this step." msgstr "" #: plinth/modules/users/templates/users_list.html:11 -#: plinth/modules/users/views.py:61 +#: plinth/modules/users/views.py:64 msgid "Users" msgstr "" @@ -6734,34 +6709,34 @@ msgstr "" msgid "Save Changes" msgstr "" -#: plinth/modules/users/views.py:42 +#: plinth/modules/users/views.py:44 #, python-format msgid "User %(username)s created." msgstr "" -#: plinth/modules/users/views.py:76 +#: plinth/modules/users/views.py:80 #, python-format msgid "User %(username)s updated." msgstr "" -#: plinth/modules/users/views.py:77 +#: plinth/modules/users/views.py:81 msgid "Edit User" msgstr "" -#: plinth/modules/users/views.py:146 +#: plinth/modules/users/views.py:151 #, python-brace-format msgid "User {user} deleted." msgstr "" -#: plinth/modules/users/views.py:153 +#: plinth/modules/users/views.py:157 msgid "Deleting LDAP user failed." msgstr "" -#: plinth/modules/users/views.py:180 +#: plinth/modules/users/views.py:185 msgid "Change Password" msgstr "" -#: plinth/modules/users/views.py:181 +#: plinth/modules/users/views.py:186 msgid "Password changed successfully." msgstr "" @@ -7070,7 +7045,7 @@ msgstr "" msgid "Server deleted." msgstr "" -#: plinth/modules/wordpress/__init__.py:23 +#: plinth/modules/wordpress/__init__.py:19 msgid "" "WordPress is a popular way to create and manage websites and blogs. Content " "can be managed using a visual interface. Layout and functionality of the web " @@ -7079,7 +7054,7 @@ msgid "" "devices." msgstr "" -#: plinth/modules/wordpress/__init__.py:29 +#: plinth/modules/wordpress/__init__.py:25 #, python-brace-format msgid "" "You need to run WordPress setup by visiting the app before making the site " @@ -7088,26 +7063,26 @@ msgid "" "better URLs to your pages and posts." msgstr "" -#: plinth/modules/wordpress/__init__.py:34 +#: plinth/modules/wordpress/__init__.py:30 msgid "" "WordPress has its own user accounts. First administrator account is created " "during setup. Bookmark the admin page " "to reach administration interface in the future." msgstr "" -#: plinth/modules/wordpress/__init__.py:38 +#: plinth/modules/wordpress/__init__.py:34 msgid "" "After a major version upgrade, you need to manually run database upgrade " "from administrator interface. Additional plugins or themes may be installed " "and upgraded at your own risk." msgstr "" -#: plinth/modules/wordpress/__init__.py:56 +#: plinth/modules/wordpress/__init__.py:52 #: plinth/modules/wordpress/manifest.py:6 msgid "WordPress" msgstr "" -#: plinth/modules/wordpress/__init__.py:57 +#: plinth/modules/wordpress/__init__.py:53 msgid "Website and Blog" msgstr "" @@ -7121,7 +7096,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: plinth/modules/zoph/__init__.py:26 +#: plinth/modules/zoph/__init__.py:22 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7134,7 +7109,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: plinth/modules/zoph/__init__.py:37 +#: plinth/modules/zoph/__init__.py:33 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7142,11 +7117,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: plinth/modules/zoph/__init__.py:56 plinth/modules/zoph/manifest.py:6 +#: plinth/modules/zoph/__init__.py:52 plinth/modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: plinth/modules/zoph/__init__.py:57 +#: plinth/modules/zoph/__init__.py:53 msgid "Photo Organizer" msgstr "" @@ -7196,110 +7171,104 @@ msgstr "" msgid "Finished: {name}" msgstr "" -#: plinth/package.py:191 +#: plinth/package.py:188 #, python-brace-format msgid "Package {expression} is not available for install" msgstr "" -#: plinth/package.py:204 +#: plinth/package.py:201 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: plinth/package.py:367 -#, fuzzy -#| msgid "Error During Backup" -msgid "Error running apt-get" -msgstr "備份時發生錯誤" - -#: plinth/package.py:389 +#: plinth/package.py:348 msgid "installing" msgstr "" -#: plinth/package.py:391 +#: plinth/package.py:350 msgid "downloading" msgstr "" -#: plinth/package.py:393 +#: plinth/package.py:352 msgid "media change" msgstr "" -#: plinth/package.py:395 +#: plinth/package.py:354 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: plinth/package.py:423 plinth/package.py:448 +#: plinth/package.py:382 plinth/package.py:407 msgid "Timeout waiting for package manager" msgstr "" -#: plinth/setup.py:40 +#: plinth/setup.py:41 msgid "Installing app" msgstr "" -#: plinth/setup.py:42 +#: plinth/setup.py:43 msgid "Updating app" msgstr "" -#: plinth/setup.py:68 +#: plinth/setup.py:69 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "安裝過程中遇到錯誤:{string}{details}" -#: plinth/setup.py:72 +#: plinth/setup.py:73 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "安裝過程中遇到錯誤:{string}{details}" -#: plinth/setup.py:78 +#: plinth/setup.py:79 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "安裝應用遇到錯誤:{error}" -#: plinth/setup.py:81 +#: plinth/setup.py:82 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "安裝應用遇到錯誤:{error}" -#: plinth/setup.py:85 +#: plinth/setup.py:86 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "應用已完成安裝。" -#: plinth/setup.py:87 +#: plinth/setup.py:88 msgid "App updated" msgstr "" -#: plinth/setup.py:104 +#: plinth/setup.py:105 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "安裝應用遇到錯誤:{error}" -#: plinth/setup.py:122 +#: plinth/setup.py:123 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "安裝過程中遇到錯誤:{string}{details}" -#: plinth/setup.py:128 +#: plinth/setup.py:129 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "安裝應用遇到錯誤:{error}" -#: plinth/setup.py:131 +#: plinth/setup.py:132 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "應用已完成安裝。" -#: plinth/setup.py:451 +#: plinth/setup.py:452 msgid "Updating app packages" msgstr "" @@ -7350,53 +7319,54 @@ msgstr "" msgid "Service %(service_name)s is not running." msgstr "" -#: plinth/templates/base.html:30 -#, python-format -msgid "Core functionality and web interface for %(box_name)s" -msgstr "" - -#: plinth/templates/base.html:107 -msgid " Home" +#: plinth/templates/base.html:31 +msgid "" +"FreedomBox is a personal server designed for privacy and data ownership. It " +"is free software that lets you install and manage server apps with ease." msgstr "" #: plinth/templates/base.html:110 +msgid " Home" +msgstr "" + +#: plinth/templates/base.html:113 msgid "Home" msgstr "" -#: plinth/templates/base.html:115 +#: plinth/templates/base.html:118 msgid " Apps" msgstr "" -#: plinth/templates/base.html:119 +#: plinth/templates/base.html:122 msgid "Apps" msgstr "" -#: plinth/templates/base.html:124 +#: plinth/templates/base.html:127 msgid " System" msgstr "" -#: plinth/templates/base.html:128 +#: plinth/templates/base.html:131 msgid "System" msgstr "" -#: plinth/templates/base.html:163 plinth/templates/base.html:164 +#: plinth/templates/base.html:166 plinth/templates/base.html:167 msgid "Change password" msgstr "" -#: plinth/templates/base.html:177 plinth/templates/base.html:178 +#: plinth/templates/base.html:180 plinth/templates/base.html:181 msgid "Shut down" msgstr "" -#: plinth/templates/base.html:185 plinth/templates/base.html:186 -#: plinth/templates/base.html:213 plinth/templates/base.html:215 +#: plinth/templates/base.html:188 plinth/templates/base.html:189 +#: plinth/templates/base.html:216 plinth/templates/base.html:218 msgid "Log out" msgstr "" -#: plinth/templates/base.html:195 plinth/templates/base.html:198 +#: plinth/templates/base.html:198 plinth/templates/base.html:201 msgid "Select language" msgstr "" -#: plinth/templates/base.html:204 plinth/templates/base.html:206 +#: plinth/templates/base.html:207 plinth/templates/base.html:209 msgid "Log in" msgstr "" @@ -7660,6 +7630,17 @@ msgstr "" msgid "Gujarati" msgstr "" +#~ msgid "Enable DNSSEC" +#~ msgstr "啟用域名系統安全擴充 DNSSEC" + +#~ msgid "Enable Domain Name System Security Extensions" +#~ msgstr "啟用網域名稱系統安全擴充功能" + +#, fuzzy +#~| msgid "Error During Backup" +#~ msgid "Error running apt-get" +#~ msgstr "備份時發生錯誤" + #~ msgid "" #~ "Cockpit requires that you access it through a domain name. It will not " #~ "work when accessed using an IP address as part of the URL." From 23d807fe25527d4f2382e2f24ada266c7e932540 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Mon, 10 Oct 2022 21:56:32 -0400 Subject: [PATCH 89/90] doc: Fetch latest manual Signed-off-by: James Valleroy --- doc/manual/en/Hardware.raw.wiki | 4 +- doc/manual/en/ReleaseNotes.raw.wiki | 37 ++++++++++++++++++ doc/manual/en/SecureShell.raw.wiki | 2 +- doc/manual/en/Shaarli.raw.wiki | 34 ++++++++++++++++ doc/manual/en/freedombox-manual.raw.wiki | 1 + doc/manual/en/images/Shaarli-icon_en_V01.png | Bin 0 -> 23944 bytes .../en/images/Shaarli-screenshot_en_V01.png | Bin 0 -> 172030 bytes doc/manual/es/Manual.raw.wiki | 1 + doc/manual/es/ReleaseNotes.raw.wiki | 37 ++++++++++++++++++ 9 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 doc/manual/en/Shaarli.raw.wiki create mode 100644 doc/manual/en/images/Shaarli-icon_en_V01.png create mode 100644 doc/manual/en/images/Shaarli-screenshot_en_V01.png diff --git a/doc/manual/en/Hardware.raw.wiki b/doc/manual/en/Hardware.raw.wiki index 1294dd6be..cc969d651 100644 --- a/doc/manual/en/Hardware.raw.wiki +++ b/doc/manual/en/Hardware.raw.wiki @@ -44,8 +44,8 @@ Use these hardware if you are able to download !FreedomBox images and prepare an ||Pine A64+ ||1.2x4||arm64/sunxi ||½,1,2||-||- || - ||1000 || {X} || ||Banana Pro ||1.2x2||armhf/sunxi ||1||-||- || (./) ||1000 || {X} || ||Orange Pi Zero ||?x4 ||armhf/sunxi ||¼,½||-||- || - ||100 || {X} || -||!RockPro64 ||1.4x4+1.8x2||arm64 ||2,4||16,32,64,128|| - || (./) ||1000 || {X} || -||Rock64 ||1.5x4||arm64 ||1,2,4||16,32,64,128|| - || (./) ||1000 || {X} || +||!RockPro64 ||1.4x4+1.8x2||arm64 ||2,4||16,32,64,128|| - || (USB3 or [[https://wiki.pine64.org/wiki/ROCKPro64#SATA_Drives|via PCIe card]]) ||1000 || {X} || +||Rock64 ||1.5x4||arm64 ||1,2,4||16,32,64,128|| - || (USB3) ||1000 || {X} || == Additional Hardware == diff --git a/doc/manual/en/ReleaseNotes.raw.wiki b/doc/manual/en/ReleaseNotes.raw.wiki index 0c8c096ef..9dd3c06c4 100644 --- a/doc/manual/en/ReleaseNotes.raw.wiki +++ b/doc/manual/en/ReleaseNotes.raw.wiki @@ -8,6 +8,43 @@ For more technical details, see the [[https://salsa.debian.org/freedombox-team/f The following are the release notes for each !FreedomBox version. +== FreedomBox 22.22 (2022-10-10) == + +=== Highlights === + + * privacy: Add new system app for popularity-contest + * matrix: Add fail2ban jail + +=== Other Changes === + + * *: Use privileged decorator for actions + * action_utils: Drop support for non-systemd environments + * action_utils: Drop unused progress requests from apt-get + * actions: Allow actions to be called by other users + * actions: Allow nested and top-level actions + * actions: Drop unused superuser_run and related methods + * actions: Implement getting raw output from the process + * actions: Use separate IPC for communicating results + * apache: Fix logs still going into /var/log files + * bind: Drop enabling DNSSEC (deprecated) as it is always enabled + * config: Drop ability to set hostname on systems without systemd + * config: Drop legacy migration of Apache homepage settings + * fail2ban: Make fail2ban log to journald + * firewall: Drop showing running status + * locale: Update translations for Albanian, Czech, Norwegian Bokmål, Russian, Swedish, Ukrainian + * minidlna: Use the exposed URL for diagnostic test + * openvpn: Drop RSA to ECC migration code and two-step setup + * privacy: Set vendor as !FreedomBox for dpkg and popularity-contest + * searx: Show status of public access irrespective of enabled state + * templates: Update HTML meta tags for better description and app-name + * tests: Add fixture to help in testing privileged actions + * wordpress: Update fail2ban filter + +== FreedomBox 22.21.1 (2022-10-01) == + + * locale: Update translations for Bulgarian, Ukrainian + * notification: Don't fail when formatting message strings + == FreedomBox 22.21 (2022-09-26) == * janus: Enable systemd sandboxing diff --git a/doc/manual/en/SecureShell.raw.wiki b/doc/manual/en/SecureShell.raw.wiki index 691426f32..aab11eb43 100644 --- a/doc/manual/en/SecureShell.raw.wiki +++ b/doc/manual/en/SecureShell.raw.wiki @@ -8,7 +8,7 @@ ## BEGIN_INCLUDE -== Secure Shell (SSH) Sever == +== Secure Shell (SSH) Server == === What is Secure Shell? === diff --git a/doc/manual/en/Shaarli.raw.wiki b/doc/manual/en/Shaarli.raw.wiki new file mode 100644 index 000000000..2847cdc2a --- /dev/null +++ b/doc/manual/en/Shaarli.raw.wiki @@ -0,0 +1,34 @@ +#language en + +##TAG:TRANSLATION-HEADER-START +~- [[FreedomBox/Manual/Shaarli|English]] - [[DebianWiki/EditorGuide#translation|(+)]] -~ +##TAG:TRANSLATION-HEADER-END + +<> + +## BEGIN_INCLUDE + +== Shaarli (Bookmarks) == + +|| {{attachment:Shaarli-icon_en_V01.png|Shaarli icon}} || + +'''Available since''': version 21.15 + +=== What is Shaarli? === + +Shaarli is personal (single-user) bookmarking application to install on your !FreedomBox. It can also be used for micro-blogging, pastebin, online notepad and snippet archive. Shaarli is designed as a no-database delicious clone. As such, it provides very fast services, easy backup and import/export links as desktop or mobile browser bookmarks. Links stored can be public or private. Shaarli delivers ATOM and RSS feeds from its minimalist interface. + +{{attachment:Shaarli-screenshot_en_V01.png|Shaarli screenshot|width=800}} + +=== External links === + + * Usage documentation: https://shaarli.readthedocs.io/en/master/Usage/ + +## END_INCLUDE + +Back to [[FreedomBox/Features|Features introduction]] or [[FreedomBox/Manual|manual]] pages. + +<> + +---- +CategoryFreedomBox diff --git a/doc/manual/en/freedombox-manual.raw.wiki b/doc/manual/en/freedombox-manual.raw.wiki index cee8e631d..0c41a34c7 100644 --- a/doc/manual/en/freedombox-manual.raw.wiki +++ b/doc/manual/en/freedombox-manual.raw.wiki @@ -41,6 +41,7 @@ <> <> <> +<> <> <> <> diff --git a/doc/manual/en/images/Shaarli-icon_en_V01.png b/doc/manual/en/images/Shaarli-icon_en_V01.png new file mode 100644 index 0000000000000000000000000000000000000000..ae9584e2a290ed9b563a8fb86a8b6a2b85f5850c GIT binary patch literal 23944 zcmeFZWmsIzwl3PZySux)yA#|sXyfkg4gms$;O-C-+}+(FxCVl|1U;R6Yp?aKd-mPu z?&rDZ-v+wrSvBe%qei`BRL!ah(JD$ZNbvaZ0000Ke2mhcM_C+nS!|`?PQVT zn0+H!p%fPUqB89g1ce!FTy>o9Cqj=3yK6znpK zIfqPomHG_r$loQggAs6W;J;ZKQ+Qw5!=SM9s~a>H}3 zx<7^JR8faxkYhVlUJ;KoXF%pVud~(M)i2Y{m&jRo5TW5bFPB}{*F(W)nj?{0s{}No zA>LA&*mElTH<@*^V$DYG8aaT#m*?l)tBhe|@7^_?t&3|S)6|P{rUg|W^laXmi$`j{ z@2`lWQO%wv?DM|Joe>)1NE@d0s8MDVBB8;03VcdxsPfU7x`SD2RD4WF8wO_Ed_1WS z#L#uJl5$*l<@p`Mn$X|NNX9&h57mFda4e)vlcs7 z;ZX7^m5Z6{37;HRDaJ*5&=lExEd>mopWd=FJgZRsD1~E_!cdjGj!}LRc@!6KoTlHU zuW9Y&Qwzz}zRPRi52gU%B%S-)hjG5*GnDivF2}Bs73@{U+_hw~hWwBtj8o4K)irL7 zP19Vls4%-Xwq^!4`ztk_D>=o){QL_ZuEW)51xx8eyvT#pvnf{6OwsMGte4C|n>YWq)4}Xk+SL4N-u1gdnako z&^jU)4al8g0G5&i)x=*fKh1upiQwy#i;cMC+f4Uqi!XpZ##MBBVh-J*3s{mr9eC%# z!61N;IyQ7LJdxC3HvXoC-Ffe28U*iRc^k+cpjCx+B>A4nG2>mNf)T8SvO5ecrWVD zGDj}8L~(C%SrGZg&v#Sq;YTXDDY`gJA(|^pbD;iovecckB#lNK*rg$ARVT-%A1?V+ zAKiID85mZ7Z?LWzh1elFDWHi|w!twreWTA>`J?|G5X<=6#`+YQgLk+Y6DMF)f7iTl zo@h?Bwx?r_d|ho-Y(n?m8=O8P&BLsg zULwXQ#sN7daUp~>$`AJ6nhmt)cq_)BV9^T;fnB;@-+zeIRA9qJIV-eh?1} zrtsk#-CeV^qww4i>GL>|Xga5T0bk=6Zw5qv?rrtYG_8c?8BLJ}kgw*QYNT$&3!_gS z9c1!IgWivJ^CH2-xFh{7Pg(mOgl=|O>OHysYigb%iCp-0ad`Y1oEfAo&36y(tb$Stc zeY?f~K>Za3eX=-T`wU09kw}G|B?yvBn~a2&6AvV6K>gRxR{6~vtcumwqn`g^}x$# zN=aaTdCt~CBsR-&S@1Aqbx;6Y3&Xbm^^4#A9(}p|~c0^a?{nR7%EN+#Z zX>Hk74F~=^NakMYJh)~|L~r&xs_;_ayi)MD#}5cIkT@FfM0zZ)XVAoGiPl2c^9CPm z*|g@l@J6|82>0^xdHwtHsn|%xotR09`McAw9+Sj7M(lqk@ca_ng_S221XHQ(3|*yT z;{S+Adh0frjs+VB(NNMAVvG_bzQGrydQH2A5pBTos8h*pkGdsYCi40%yP57p@LPPM zYW6VfLwS2Yf6W8)P?zfW~R7_bT(#cf~@AU6_uQh01cUZ+Ov2Kha(rJ1%(c8nxH*;9lOX_GVZT z6Z(20+-8bh25%*0#WWRWA^LZo(SaE*dBlg-&+yzFq9OD_M4_|Zc*rZH>pKKN!@5_2 zvqPN$TUO9XVPa=(<1U#y8ehv2;XBd3injcaw4R}3n?$l8d6qY$2Phxph=!D=@)#^Q zNTP~1ZDLsREIfDhm{N7g+&0Ii*o=HOKEG{Bb$BEqL7PQ2?B5Cg$j-QSt%&tM^*+Q+)8Gq_f_q z>5m+Ih+#pipRALPXo48D2%+Hgl&%+ZE3#5kixVS6qgW(d|1fW@ z*z4f%Xr}DL{unw;17sEH8vK|lS*6kE$BuycmKwsgmR)LeWB5>F(ocmSaqdQdrO%#SSN?p}8dB;p~Iy^QnT@f6#?QDTP0JiUufFv4L^OtU+)2 zrdS2B_ZYXFG@?_tex>(JFX9ePq^1jo)E!#}1pJ8Q#N80bvHabpd6(Gj0#ZCpy$COI zM;=Kvnvpe!>zl5GjYvUhTznY$&rWQW@3cl6IkRF;{T|D<;tdkpvq2Hwl zccet)vPFwWeVC+X&C3|VUgRmt4nL-lk#9IZ>YQZc(YqD7VPZkVNW7!tw}WFOD+r!Q z)QEhlg)Wg{8Lox_~bZ z)3S!MMpz4%G)mg8+gcdabBSr^zQFen%i8DeXNCCGD_~YKPr?*)!I+ZR>X;&`Yxn6* zkT#!mU@Q!~5rQq-z~)HoqCHE2`lo`LlX*?>fFix@7n_$bWaMCTXGTuC6zdjh`wxWa zmfa#I+0)5m33&BT%x9Z7cxGoI|%))fjS6ert` zuWSQy$s^Q_v#R821)d`oJYiW0Pv?G^BuqV$8~h@ud1N@ehf_aMUg@$+Scy-@7Ei z*odOfdkOsAR$$!b@Nj>q2VSO}^p=^N0C-%zM_mv~1l~uMLexRmca^JnJ;JnTa@hNe zs4+Lp{=z*OQfkwlTpm#5f61rX@RFYhNfm@8b=Z?terNW}rm*hS7{O z+RWk8gZOiX;0AC95#0|vF6jbOFQd2J(#^X7jmAhhNx@=8XP9>&Q%HL^KU6JZ$KO(t zJ(-`HPe?LF-q%FT(YRnsL2)jIi*;j|;Ea^==}t?8+4kh&7 z%z-tSAKHD6hIltdI6Ku&X>$L&p2AkJJNmCY1y%nC?k z1Z$g(`Dl=;)J1d<@gE<_r1KWKZLX$iAY%wQVT8@9en!jRjY-MOhpRv=p+luZAlUp`R%Lb@1DIDSm z%<)Bdiod+r^5AiqbmH>!1Oi$=5-0l@MVV3O+FDP4eO>tLbq{`jV2FLL;_1~{X+TTc zFBpkJxMj)&|?g6qbFjQ{8+DyfyabmpH(iJIM^ob0=M!`Se$W0hkp0_f@|X6QZbz zBuj!ng@+J2U9brSbpKq4U9OT4kZIm39L>4f7Ag%$AY;wDiWZ)KL_aX)NUNWzTAxqZP?Eq26j_88O|35`lo)dg_i zBCB-k!TP59Z)3~DrsJaxe>W1U5Zl5SS5k%b24tQ5B!m=7On}ZHR_h}aGO9uS?xTXN z8CTnLVm;A%e6HP6=K9e49)+xB;(p4P+X{8ktro6&fq!dhEuT z0Pd2o0IBbE!?+?o%!lukREpAKPmP)`(rQp(8=KW@;+Mkf(#NlDL+NjO3opMQFK{Nn z!AJq=-HWOGa8@C3^RzO=MEg`NJ}v;5;%7aI#P(hh%neDq+?NBz04Hbht$EX3=tyq& zFE|e~A_N`tZwn&rL~w(%kepb#rZ1PtS2?_)N?%j(;)tu(-6UxxAh)iV{X)8LN zh*1$WAfAU0O}O?imu}+BiK|Dx4a`bw^hHDYuSQX}E?aBM4^qD;1ZVI2kbJUU@80{Z zQ~^(u9<7h~#ti_>8O<|cK%bow3Zlkb{o&ZZ0wzq22F^7%eUHV@ZYSa)^LP4ik%;6z_cZ^G;@}33S4t zYPk9t$)G+Ti~V#;+0}aILLsewvPZT=OM4W9)6aRr)wlutah3tZaT@%b;>26BRMBiE zCDiXFEvW@Bct5E3xH}<4Leg@Hj*yOhV|0hHRFkA2WNOJ0acnyOdg{?0lLN#mfRe`& zcnmP{?1zRtrD;%%a``pAIm`X*Ix`gX+%j6MHJ$h~6R`bID3h4;LsGBQ{(;@n0L@!J z;xeG~5pXgdv&y8PvI$0JOs@uCuLP6a9YyFkRS1axd}D{3H+ta_SpmD{TA?kvaxEv8 z!Xts~a}*jnwlaXfrONP#Kel+UpCP3D1<#hvaUU(Tlc<|~^Pm;cQPfWKME(O09`nOc z-zamnxVINPsWrqB?Pb!_rtk&?P4&_Ws#U58__B3r?6GF)mJN9H2WBLqC2?;p>pkpx zSM=#uCkE}qCnEhXMM5pbM9e;sAz=gjR|p@JUoYB;rI3DEt5b$p(S|BmtL{Cg9QgRd zm{%N!jrb9I#R`jG$2G;cf$y04Mi-MdNTJ*;p_^DWkOileGJU`V!e*yF)APnGtO6OJW{USx~b*O zgHvj`4g20oUHUS8Z~utg!r2_9F2bug2RzAeN-QPQlk9=P08&ldNEY{tU`bJXENR6n zq(jib^nF5-gQ^bnm?{1H1mX`0$G%w2v0+FXgdT4&nEWMkBP#E$0RXTtYY7PzISGmX z*rEn)OlSFj6q4-|B^)qPmttZH!NznRR>@|Jis7}vic!g*hyTK#X7C85h@XUsBh%Bc zwKZhA&@-T`4WliF`V4S(b5V2qi2n8&Q?K94X)VF?p4jsokpJGIVwnxOECX1y!^W0u zh}HIfCKUA%wL7R^!Jj!@q1)AOy>Do#jdtov`2GNvjxQNZ_@h_qVT4q>m|%zXVb*D$1DV71VIkFBK7Nj6VsaMK^KC$f_!vkG#O0ILO-(I+FtM2 zI=$-JeW70np?vnh^kdFQv?21;#4uPq%@mc0aM~~Ubku6~B-a-xe6N%(<}RPQhiii1 zHDu#So>2lkZTD$t){2Y~fBMy&CZOfn;#kewJw1JIB%ld;!)u<^dzB|j`$gHYI7==g zdd}_Sygs`pwB-VW>o-d!;X)~*NR|t;G4(UER`iVtRmauW_H6eCOjcbxnqX@S6_-in zu63xbZPoYbUZJjwgsR^qswPc|0sugXwFVs-=qM`in>pGuo0vPA0-3$+oj^wl0Dz!~ zmy?N^EzphB6liJfAVhxN)*FiwMID zdhvq*?1643q+a%R4zB!OLgasN`9Yt57qgI){tFLSr$-(UCV#&hB$H&LQ%Fe>h&IFQR za`kp_Gx1__aHaSS@fU_9(ACVv+R4q@(Sh_grirPeyPFU>IjElWAK;)`Gbt}n;Xf4o zzWxL6>SoR&2fE+{^#>%t!p_Rd%f!mg#Lma^_x7M#Ma6%%c5wZN7eW4H@iK8@VPj@x zvA6%X7Orkm9{pZDiyWRsPxLw;L_3?VbL#_$~c+NprJ*$~n2a*!__)H)8?X0qsGCxPp+` z{!QM^+TvdW^l$z7UGu*g0#f%+{C|`F4}bl!<&R(aB^}M&e=C)f6e9m^FTc5?nYB6p zpO2<|941_Rrd&*XY<%oYoTgkROuQT%=1kmNJlyOi=B%dXCOm(Gl5=o%GjT8j{)Pg9 zGh2gj%z3!DdCj=FnRrckOqn>@SwWx7Of8s9Sb?m(Ku#bJ(A@NI5Xvsrphz&W`@2=Y zq0B*0X55^-W?UwGOcv%`KqgKO(3`2bDI1doyNQX3IU64vn4c;dsz5EodG%43FH=KWo{u4#a#m&>v#a7ux+0+JT=JsFX{Aa@dL{bCgI#)LrZ@K?Nr~V&u zf`8Ff7Sz_!#rtpi)q&1`UHz4i?5zK|ij?$E65uy6`^){VCLTcZKSKcW<6l)~RwfRX zKv1^*N2vWrx%GcSV;)meQyw5M7n2zWh=82t<~&S%<~$%8n{rw3va<2;ny~*B3I9ZQ zb+mBvG;slnS%NqK8fQ>w{TXLc+CS{0`*&MBt$-koFtKv-v$B%^HN2#PEWZ=#e{@gq zcgj&z>@5uST z`1KFE{a@4og8m;R|1JOikGuZIUH>f){I`Vvhh6{UuK$(?{#(NT!><3|+y(!yJ8Yl> zXrbo`x_|C-EWroedqbPPlaU0x{r=ADC`|^Hz&Xk4x&i zqjRw>Q4=p)akuGyGFLQk&ET5RO#W%1C|Dp(RUn2&8DkJ);9>;cHx6*U%@Uf^CUSf$ z3t0GCVJpqbJhwi7er;V6d02R~&=j!r^wKFZySzMtYepItqz2!|DoO_hz>NUY)Xb-a zH`j&65r?Ie12;pAFbP66?Z`m|?_(vELw7TTA?x?arj%QJ($EZN99#5c8_YZAH`i^9 z4`zc7unR*itALj;ch3UY4UKlicIA*Dh*-R)KfnF*yz07~GK zm)~YT6ZV^-i%86I9zXx`j2aqTN(>}lge|=!!W*7<5 zjL$JxWlP%GRC>&k15rHx_@+V&nL7p3wdv@uBuE^&dEVqC+PlpP0npU6$B~)iL={g= zPKM~(L{S#}RWGHfdE6uRg*FDtDt+_R0Hc4`8KFo@N~*DK7(-cDaT|M?6|vux4I!|W zQ6hfXV@ssWMVlH%u}Cm}$dH9lgWsFG5AlTA*R z=E%rMji2k-z}_Ui_LsGN-<^@=#k@5a7;rESoqbj6V$7I=?t^P@h97ddzw%6>rS{9g z9gc;*9LgC*GmbUZXO8zhcnLa;HF@vI8Nr$%)-q;_Km-Q?uelVjwT6;~VQ3P9X_cw? zJfQ_Ii&(-AR^1JGk}on!dO(;NbIHP=L5=MZ=0NX1cm}dcX>x8f`>QJ|4qd_b_l3<6 zYjno-iIg7=z=MO*H*S9U4NpvjQ_8)MpG&T1Jr2@^qLwLCRkrm>;ufcqqC^j#I^dXS zEuc-L99fyW=}+!N?^{cFBipStqa81PkzmD@6cYnuZr%bPPv?Lsl>Put201Y?@i5^S0HLYrJjT>igvE>0 z*KPEAg+nOhg9!uzo8MlaOmLxzz4y@O7Z=G{SWxcQJ&hItDNk7d1t^VG=bh3^g?c@7G*^o}ED#W8xUPp+z7OL^L*X+kO8Aw(W!qvU7C!Mi*qcL-RIt zl|c*oT!~`e&zZtHdc6ap9v4Ak8BY8L{MR}ur5wTNWEy2~0CU?3yFuW~ZEDNI+JSIn zg770O2DQTQuq#EF@njZX8i%FQqOQQ%d+LDEi>DV|9MD5~&J0{7v@xfS0bL}?)QU%{ zyAJEESdQ(N&_~C|Y(6(uYfgPgyyxxLc1lk(g)%iBr+O#rZ8#rgA+fNqblSbx=;`V0 zay^gc>Doaa`(6t~SXo(NwVEbn)T@UD*<0uLteDBYJwlV)-yeyY&41c8X`k5c;1j01i8~!-WiPZJ>a$e*A)7?eeRX|Z<8^7O zkjaho>(?*3a|B56->w;q!wc>3z29kAdLLR*q0<#0G&(j$CWkH^PZ*t%fj^!jM6f%Q zAfv5~^WNu>s=mH{3nbZ>LZ_Zb3m<_(5}%ZWu8<>$hx6Wx%v^VH^b3{&?(a}*>i}5s9=KFEJ`huA0tZ-|MY0K%=i}XlQ?? zH_Tq$ekE_<{o_;Py}O6Uj&k55255+<*Vf|5BqH)^Ytg%&f3T>>pMpjuYG}9Y>({1W z3_yuuX2jRPm*Z51B*mpYg*7%Q)$ybjCtf?Qddo~#p}L;aLBtyXEJ}jpu$>e}r@#f7v8+ zXi10mxMk8B9Y(6M;i)MZZ*RVg%uJ?JA8Ivq^-vjNZ^(=ilcV|a-)f}eaDzeQ*)1>4 zseO-w9C>-shf-Kx4hLf5P=Qn|tH+7X@4?pYdemH`4^gHd-Qmh+KPN#yf3Qm|DWQJ8 zDHR!bxZHJ~;94@C&J)vmy$1OS>=v>R@jV zRgAgx-j}IFAsrlGWoLI&(IpI>wRTzqFXA<%-s+TG?q+dTj`xylM`oW3_0ZQ522hY6-Ed6P0 zX1`~3aaehI`ETYU=yuDsP^YJ-wDk1inwnUkP*By|1;=YRGT# zpVRre+L2>sB!)|3`~m{Ho}N6MiV($^p)e?SG4Vo&9L70<-t5Z~=D5({!2nDtz612m zoTAcq&}pl6DXvt`S31gqhsVaL405B{DhWD0$!>5_e!{uBcH{b-Zie@qr8L(0d|wWk z+YKgdk?tr@pOu~WvSli^uxi%&^j&q7aFObNV`BLUFlpobVli(nNTD7#M z=Ix!IkX)?QdWHOsHx&!+6(v#Fy*XZlNrwA-sB>#2%#P%-WEGbY$*fnZ=g+3?xe$t{)N|#Zh%NfOq9<4*M-VP=Bp^czB zXC>5Y=YsubD*~-LVC92R;05A}1kuJ$cFEly8>%KI)QlD8rPmtAK`9wgKC3EaLvb(WDQ68!qGG%jpQhN@?`4XsrI*--+P9U{VH31f19Z)pLRSqzi zfIM7uLelbY9@O7WK&z&NBil#*SU|h6_`}+2;=_}0x2+-pm|RSrrwapi2hEUpx8!YR)Mx?!XFs*rI~`U^QEGEO)U?T(Nr|otxQK zdD+`qJS}v(TzN6#mV!e7T5V44-4t*woiB%Z3V5`I&iMS???b9@g;vzQ+^Nyz)$$zI zpC|5@@6I$Qna@zzmr540oxt&6l*lB8aud4EzdV3rI=s7w^tzW+-o9mW^p45HIXpX) z<|S0pq5|$FPAN+uS{M(cYU<3q<^wp_U%bEOEnuvu_q`GOVEHDTU1Kjvfo@|cAOCV~QX7q11H(81A}Hcw`a{3OLuM-c_k?-wXYXC3b|OBU%cmD?Dw-eW z*~Gh%ZHv#VcU)c~E}US@eaI>ZWzfdB;3^nh$K+PY=WK3BUl+d&ydFVpkPArKH5Zva zoCVjxd?`oJn`4D!#SiKMqWDZJ#m;D_k(%a z#XG8|+nh9)f?t$5%Pp7{`NcL0sa~WX*Nva8ci@zLSSf?YB<*d%Zy=9*)opWS3~nRp zV=UG)B>La&wA|hFxBG6c)uRjCJci*Z0g^+L*aR-t`k}SJ@)+SC0l zuaFF+JJys_RhhPzOCKCfeQzXfE_O@k;Mjs?AFliRG&5tUH{v$ZtIag$u>HO{W=4)f z^3oMYNf(yr9)R-OIrKc|;&%G_S8*Or->@^A-e{u4MF~KKdU#B*I`|EeG*6Ds8)HGu zPrj~K&;mP-t_i9_M)B$4>R|L#oV3n7 zmjT4wWuyvmoGW}-&k)I(TT$OTD`>5jNCncyxJ-tq zFKB?6hIFD%fZjdtJ89x#lq?@a87vQ9jem`jCg_mle!!C9OU2BR4JFG?3bO2!O4M{D zyU-KA(WEa&@#oQ*xM09p@#lVfH{Gla59S9@dLYM72npWqFHhEKFu~doXayrMg)zBk zFTqF)dy`0-!a(~a%MUPWf0ov7+3pU2aK5gZ+U@uxfM!~=XUUeDLEO+e1VGF~GGX-D z=0;47VJ)%ae1wT%Wlah_wqTK7_@$XgdO;`r;QxB!_7xp*b;fGGNOYca!p33>+9Zw) z{evivo8*pa)p9fRIiXH$ylEcOVsuBt({wzoTRP>WKF&C=>r6&}mckU%yWaYDVLJ>M zUx!khlhvO~-jz%Ytf4S>XA0T`d+ElbuFs;xB zKWiGRyaFIIb{~3AY@JmXq!MAnmARYpIdsua@k*#1?d^dPCOW5Sq0mU9xYyMc^rn}% zh`mlH4{VH^572j!w)xmkPR(bmHm&$*C@N*+S@vd|yB-=Cc;rq7v(n#6<3(wyA0xMl zzX}IOV__ILCh}|=MStxK;L+3RCpN(A@I!fHX44!{S8v>$IAH&jhYHvEEn*~e&_s5G z6!NIB+4QQo*=@0S7->)RqeADHTUT`)8z(2H4n&CDyLSj2hq$9Kqouz2 z^x3p~nq!DlVSf3De8N{ll3k0e2(DoWvkQe6;i{auTp5}5wp5rPXBbSb8bcEI#D4a4 zC6wsZ#(D@{sFYs{b55rBM=nm@Zo6{71+B&-NB$-m&L{v-yp!VmGHFLpR*-X zhQuRr{VwVl-_5YD)Tb(T(ua23DP;PGqeC!?vrV;miZB%`Cd=lPejEW;dMqVrJ@5zw>|%LopdaEEv6nV9xbMUFK4 zbm`YLguy5$hvchJ+!T(wNf!&zOQs6HekLf!`rU=_J@n>7Js94?Utiz!TjIlYJ2Sx# zF=L82klSdPib(6nAe7^$@W&gn8?#2xa-e>qsygBg>T(YVYnVD6oML%Grj8@b#V)7Z zC~?3FU>%$#*K@S8@68VM27C>>r?8eGaoizuOrM&`_?P{VliLyXLY z!!cH~DG7Oy;3iSOirB3<)Xvh%R|rrN78ZG-N4)z1R%_=EO=%+xX`j`)V7(dIbjz~5 zlBg+wqy!(C+)Qk} zECFQJd=VLpRa+uEf(o0`P*wG(fzt`A_*Ml~TbDT|ss?lPGgJ1fy5`pBI*Sc;r9EM9ec zisyhu`@$<$%i4#=OWBZV2R8ck;o=rf+e}675bsG~Kx6;WCW}xz6rLtir{$jXRVViQ#NbCo?VvCV16I_2`#Za~g!$^+;u~`0$ z0m4{X8)O<;q)2J!g;Yi^a!;Fg)eGiNyI1X(4{PC{1IZDRafSz)n4jpG$0`BNeh#zs z0^`14sXQ6o4ehdX3U1K?`R8;;A}4Y6R`j1RVJa$O2(#yHW_})HCY2n*A+iCia1IXuHBjq-TCbBHn_jC%82gO{Y=E<{^+fr&WbtDC9UzjDg$LXo+whtb|)BamNtA~Q`pSQ;8wXnjzvLwfsr%ZBi3h~&ifr}?Vw;X?1aKQNu-QkvHs}z zh4c0gOi$brOcuN|-tg`|g~p6Ns*GC2#Lk?1R3tB&A&$!JVBy|SAj)fM_C!LBwZrEm z58pM&=c=oQe?5I*44C-_&hNaeUlP5Jbx;lKx_o5PZHZ92{bZycLb%`e4Xlr~%r0@{ zE$W6)k^y=6ldHLgmPW{N?XTqhUSo?D%k$Tc<|mYQ7fMeSMHTXBDGs)@&<2=P3WJ5N zuTa;e6Q|eBp$t&DQ!{& znQhfSPRGGk>qiOx3NV+O9Okx?r!$uW-3|;Q*cuH!R->Hm3l{^zN}vPcW#G&Oxu4n| zddH{43e@!0vJB+p-=#9PN6QeRc~&$?b1+au+AzwIwsepW5Oy zgj|m@alOSxw18kUaRUxw$kaD9ZPQE%M-ANze`wApZ)l2!{n%-~sql>(b3B)-KVfJ; z0EOqho4XzW0|44Rt|~KZy`B^}*VbHMKRpB}(TFxluK`BY%!strrO`~;{8Z|YLgT>F z(s}^)wvK(uIlia~L|(}Bb8704hzSK|PD|VkcB)WY~TCt@gC)PbNEQaCk7& zjd$FF7i%mR5BVYzzzQcb{+Q(QZ)1C92wMrJM?+@UXM>73M#)+rEvc#4*DEmKi2tYmxV4j?w5&2t^@erJNTzdSRYzfirVqvP-ORsvZ3?babw`MJeD zbVS?~qC};mcS`XHDh)Kw%v`~Ab2k$jVd7+<(+gP0q)gyiRcRgO0oG3N)MjiTal`QY zb+gJ?H*95I*hX}@UwU7NJQ=%CZ13B1QwdeMZW|u<&(C`4Us&Tb2y%Spbh*l+VGU`o z8OY((bN0LU4%y=+-~piRNi)4r#h{JQK;mT#Q6ef!x|FaHxA|=y4hQ`Jl8x04wl4s^ zRh3x%+-IEjiFj({79Nq+V(5jKQ7TMT5|Fo1avxpqjqEvMrvhOqbeD&##2Fy*=l8WfJ1Jw2&0l;TgsXEj z2L%ND?^o`q-+ws6aUku>_RX0uy)1}#3vKeg#-pI@-%n5s;{Q=^=K znebh||CB+J$}py&&&c}2PWv(0yL29AwI%mh;^;>|;mT>=InGj~JRX)Fq8|ui(dOql zMM_6v-x2K7JLLV`op>5a_}c1%5&ODV?2nyN!Xay+C_WjDFg3{~`74Lh4;0pQMzRFl zMZ`f;!_ctsmiRe0pQo3rC27ZzY(D$13A>Qd=9k|vO&SktDdyT)MyWu^94F*1j6*?8 z6FNwYPupdzHLPrw2qlB5=1X7xT=Tsc2Kj3R8>Wo7*>SPB9aq=5b}N*99#Sk}4c`_7Qo06i61Tg0{Tt?BZFJ zs9_`>)Kc`LX88Jyk6R_DT9nQ_AIa(WzAtylA-G)U_Z!rgRQ9qe4+ExW7hSX(o|jpV z{pP8Dv=rN6YVBY&e+R2+qAdn;=hqBkA`T?JhE6@!&_hcF7|3N~AMATlJ8*{rNWyJ> znJLDnt+HVXQ|34=W2Z)_zN7a?2obCY!+j=xfTWGsL+Sq3BQf=OiOfhG6w6=%=MZ6X z&IV)Pk}b;knRFl9&ISO$68Zfs0Cp^J!abRCq#~?zXKlY#V-(#WgHJ0D%j2=Z1#@RC!ZA>O9gm- zfcyNM-;>8063cLKBPahMh*ab(vM5%s?z5yHcplB}7pnvh3oKryx=D-+i?~E0&{#yQ z`+64Y9(!yX%R*7{912UbI-4&6qt>DhuFh%B;~Kb7v*r5iy)IdXjp4yk(!k`@J1*}xCg1-Y=&LZ$AOOrVQPs{Sf=`EYhqP4J|i*Ma_{!3 z`-;J;aM{7{r{*M7GQW3QfdGRgqh(={0lUth2?v|p7eD}j{vXc9`ZMx=T=qw-;4i## zD%hTpwU!|Sp;~1@(QV=*tm~ccC=<;zQ{#FsYPU;a#^1{ECVWG-ay(Dm$eW8EGncR;+=mKwf>uRcK;oS^n z1c|5cyXqRgV3826z^_im%%#K%@kYRfhz%6uvU|yX&HZwS|JwShC|Gj}RRu>93{8RO z7QF?e=Pn(M*bcOvSBfb_~)yHQts_~0BC2s9j0c9=Qm5J-i5^nL9KWw;1V!@kVp&E8~!+<~LX zj*=2eWYIfFrC=U)AR@zx=awUbhiOm5fzxUh%Wh08PLZ7eeKueQkrnqYbLc7|+ROk+ zLQ$I{LqMOE8KF9xH&k=K`^0wTRGCX{vkpN~&l5%SJpRST;;!q7R_aGHrRIm~W1X5; zCc&CB>nevQRC+c8`HLuu^PkX4ZC$vQh>rCEK?`3U`$F6`o6RU1jN{cSZ;S zS4pbMK~(SZLN8dePgiBLYy-_tSL}%_EfDgavy`LDCWLd4lhJV{sL5y}jA3cK_w>3e zevG*lkwWH!INF31hiwxP38D@7yfL7mG|g0DC|*c_)$$}Rj>VTUto!^vbFZd=ev_qDq-S(rQ6-;BY{Yo8(37d}Skt`(+9I0140rBQ z?*+g8w)9q~*$3GoJ}ur!9|x6{FgIJ)n{Vu;I}eY)asDKz2T{dbnAh7!9eYl8IZ@u` z+-j)$NQfK3iiGFq`gDp%HeMt*Klh7Q6IG?+}>?hq8G#Cb@D>#Bd&zY>U8apXR@-a%7l|kL!mex{# z>c{1%OlsaAj}R^mUE2iw!y1~Qq$ukm^=nDN`CERx)TkZD%@KB9e zd$uU5V#J8ORZBIhDAk&^N0$|=ZxN$Zh!v}dt*9DBZLQkWNR>9!DzSNMwS*V>K7PNy zb90}Yd(ZRSd(ZitsCja$R5H7l6wt=w$)w~2YdoEswrcZVH>@uAyJY#93WZ+p)vvlA zYRg`EpRdB2LvQPjmiwM&yzIh-1bk;TgJU;9!D0HLneMSGpeJzI|2vemn$r(b$D%&cX}S zyQJq*dI6fKPTk4kxCU2Y8@I;z3eVi&=b0I}Mm*>0Bstpd;_ip~HXl>$q#Vni9N+y$ zV|*Z*c4bHHGaP>#yJlJQw-QSWbI(OEbs2R&$%6J;_CB~5=pW_%VW%msaFM1q`kEeu z_JDPB`bIZmA(5fmO5{MjI^U6I%#;~(iwx;2VCz6HK1W8r4rdWwuHh{#F*+VOIKd1u z1=-}L6?;roU1x9!>eR=H4n_=u9Eiy7mp_{Bx68P)Hv%BFW&UMJ%!Oj674mAT5Qqld zOm7kEe@2FxZ1Db^m#sR1JSBvz4b=x>ZhZp-+M|Pwyc(jZg$4N}6s3_u!BglMVwdT@IEMP-Ol_XxkyG;keY&f-@I0O1f890JkL^ns5Q&{ zFJg@=UQkTP{8YgQuQmL#aVJ4tQB7EN!k6E`L~ziB-g}%^rK4R=v^u`- zw2)R)6|eDxbiM4wH8n5N`?<-UhF$4T#%q@xqS?h|2z;+zaL-2ZrHv&?g_)%uPY1(a zhf26%t2;F`i1QuoC(x-?3AvTkN6bb}qG%OyvlvdZpgD8*x_JYGK|S;< z9?tonYLuAUgm&JoP1`uyxf6kgI&%l;odi;eR(xK-PL3K9e&^$J#XM~Ee!hik`dec1 zLDk@z^26;d%s8nV!l8@2u&0(nGdKJuCL{k9Td>=kuS;sqK7=%PsG+-4bMbp#qFpf8 zvPn){U_e!u?Cgm^z}J5`ibtAvoOBgY^qZntzg{$&$M6R;<8r4=bkosGfnX;H0A`4;7Ze{`m11sjcpzFOT~Fu7pZ5+M8KMY{-0K z$Pl}BBt$ErvLcZ+)*~A*a?wx|#;*TRsM^FjTj$O&C_lJ#$yLy3!YuoTG?;l2-m1IV zoPKJJ67-v5V{2Xv5~2*ThvA5(l~@hLlg>XT=Tkj}{(S)Ut$(LwxsjZt6v5Y$<6701 z-M<*ZL$#j5HH0T;Vr8<6Qmu`qC#sw?{|2^oc}n-0uJu#h_%yb20^8-dnB|Y}^rDs@7u`xBOUb_+1lK6Ijf|^UnlxAT~daV4kofeRoP=H zC8*+1OAqtW6UWQ6H{k$p{=+mR`@- zJ^7;+khmNlr|ISOMWJ*7v>_=}0UVbke51BdM7!#(YCt*E=E;GB*NK6U!)sMv&70>9 zeRO*cA6+n1NrGxvzYn0ewe8N^SXwlmI|*qfuVbJ146LrbRz3<|BvbRDhk2dpppidH zSRaA12Pp8DyYXoTd2=Jsubt|%+;lfkih_~l?}T0oflLfnqogy_vuDo+L^VxHW_O17RPu%7t&Hh>A~LcB^?Lj3Lj0srwnBPFleDP!>tCY zbnFjz$loSiyNLZ!-t4{=rRWW9yffEPI zgte_kBHXh41wXx@N`{3^{epl5wZQIu5P%0Cu(J+=lcWu6HFZkEsJ0`_yfqO*554~lzM#;cFZpW zog=o;KSh^?Wo5VUdn%Qa8NtOi%255Kr6tQ+7kcqGtLy8XT`W3SgmdpNAb%*`dCwb; z0!DiNxMTTw-So6Ah`6EkQFrik{ClSC-Mbr(j>07-c?o#_lrkyq zI7i?wJ-od7K=jD@uaBojJniKT*qjIlU*zQBDXOVqi!IDADS`6XdQ%I8mS@W<>hh?pTjCz9!`HS7kn!fi?hfHE<_ENDx3kb`1p8Uols5iKK<>@Z67ei z8L_K{ladVtbphQ04>*D$f9~=|hXdO~0tzc=K8ok5g$)+*bheG}#li0$05C^KN5gsS zgV_N2IwtP~?GC_do=(c&yMJFqFp=~o<6(p&??gLV=gh2r`C|B?vC(<5))gS74hL3( z_J42yJi~xo%BI-c*u(+dM+NNWO)$0~`q&4{ug31&m(YXZfYlnl-S(I%ESkSkS$7vG zxSc`!Q+Dtg`YmE@tQ6E_KQuHr5v%OTi4-ym4K)?hWo`afESGybB58#Ozr{c2#OL2uE#`cpsZ)}61UWO6~9$eqbx=Gm#nE78P0&O@oERFf=cw+ zk$_V`&mrc}`H~(o#P-8P`>?ov{|v_d{b2(PqewCxuk)Fd++7;<*{EzR1a?zeS{l%v zBv-yOx!SVPL)#z`OPy)rO)8O{Dz2zt0sySBp0UAq$?yzwg7TTZr)Sj?k?p!E5LtjF zl7qFGc;!BSdsquE%Fl-sn9@N2&8zVt-2~UD*}zS^X2}}=cYIr#z#=#~IVYm^ z{%jBlB?t?Po)-U&uhsTCoLpR1)rY+*pTd_0Gm1Wa63n9*VosJi;G_aq|z9FYvd26#|Z?l0TM|MIg@xz zC;L-1XiDhjRO1%bOtiXfmtlE0`_+_Z>xBolKKj*s?0JM&vgpG>z~8!Jxuhx<|CHS= z@+R5^&V$4gbGo!mxrc860O?{PR-_i;B)|5UcwH0;j`) z>~s7*-5j)>=?)&NqCkLv<-M@>8@~CIV;2-|*TQ+_Cie44js}>bOicW$td*6OkT5)+ zKX^&XzQZ|DD;n$}r-5Q)Yl~f9e+;J7!5n(-BE$Eo7u+(oF{QcxFaX_mwx(}`bn}_w z1izeD#nbk_1lI_y7ccY{fOaIs7zi-fSxRDsfM&u>az7ZA!v}d4Jy?OFt0dyp{TT!V z1OOxkQPWh(QD0TX46qWIuDt4g;&j5Ro11#TQ-U*ajZPO3?7+arB^FgF3hUg+1Zu%FJx{p z@94Fi(e&-$*7_UWQ;KcBZ-YfV$oQumlj-kjmoA6N5Xo1@#ZkIJ6W#m=A71lFIv^ z{|~)~LudW8uO!E~|Ik7*rg(AI^Ms!86w- z*CQ((-}7ZaolC#wC`#*0@*~{1LQD7keJ!HQ7w)4ks2KfX)R9 z4n*&zF6E`W>MXI>3z7`hK@Wl6TAL4HWiL}h4=1WyJgdxf4$RKk$IpH5hYW*L=O$YSqR)CtxyPFL8mIG=!GrY?$7r$wS7L4QO1V7jHsUa01fntKbw^jo)}3P zAw;#O?_E6pNX(<135L7_$MA`;b#uVfH!epVs-RV^e&+>t|qt=m~87 z2!=we@4o>=1hR>Y_kw-EB|9I>-*&9jQU%7dQOF^?W1jSy`)8Gevr>Z=l#gQEaaJck zv51YpPYK6C_bkpo5YyBdZjY>v1BXdv89b60N0BM# zLd01AHL7YKquv#|g}?JTF&q>*#2(+dD;3q{n7z#Uy`4NJ$22w5XY!CHt|`njY$33q zX;maiRkeq}Vc#dK++KrkwX<#Yt?T45Ef!e$MMAG^2tN!8UFjqFWM5@fqB4n#xuKp4-U3ZB1A6JKn#sB~S literal 0 HcmV?d00001 diff --git a/doc/manual/en/images/Shaarli-screenshot_en_V01.png b/doc/manual/en/images/Shaarli-screenshot_en_V01.png new file mode 100644 index 0000000000000000000000000000000000000000..b12b44e431bf5009428736ef24ab48e6c5bd1148 GIT binary patch literal 172030 zcmeFYWmH|uwl0dh6WkqwySux)Gnu$f+}&M+1PktN39i9C1P|`+67tAeYwx}GyXT$z zPJ8eE+em9;RDJ#Hy}DG5QL|>0ijp)k0zLv57#OmwjD#8(7$hke7z6+g=B?#s%#9cf zjHJR_L&sIk)PvLs)WA+7pa(9^m%4( zZ$Vls3H(0qwX#l!cQ4oBK5O~Ha}DhaSJ&@`{JXk^elb7>#J$4rX0AU|8~+l<)^emW zLRvrnp%X{sdocwT{OXO#C(QBcMg}6|ZWs1>RqXAQ>I;6c$vIIjWHT)^|DF}Q?dE>JOu^X*22|JASp2}AM!k|L{K`>LN2UtXV{q@9r^Sk{0w3Uw=&t7eqFJ`Gi;fe4{ zx87WNbZ17#DFH?>jc^hOnV^dI%w|~NTvw$7awxa&)D-A;HPjRtZwW!;bo&MkJ+&WH z%w(xPsM%N-FRB0(ITzI`%d7A9^uY+#$Eur_^^S8Q+|O1YUH606BS=gKlB9@%^D|O; zMN_ft69QvZ7A;F3j7@_u>1!K~Y$_dFWs8YCmc2e0daV3Rw4wRvIXhDN(R=xjMAc;v z{ddPaAvc~xeL`{#L8or?3~6az=cEwWxD-yR~~-9^$&!?eaOPRdi=2_Z{3N-{^eM`gjUMg zLohm=2)9poB8OJaC!-Ltx<^6+_P*ZB8v^4^$Rzh4S8@UKgA0H(e1lC^U-J;wOat0N z^x%4%hMb387F!ENTVYn#QJwKfq}Iz9(AVt7ob-?9&?>@>+EVPwjxj|)U?UAs1>=Cm zW68)g4F~oljjd-QZ7ZYb_S@W4=rTkI)+Dnur&=fFj{~#5a;)b24M2#3+upCfhc(b} zpeapi_#rue|Ie0Yjg6sE5?EL_Gs*k_1rfJP(sZZS799`P=!e7C8SHbGu44Ap(n zC|DqyYp9lsY1ViGk(8CcU38<>=%1R`SVG)19OmuY{PgW+9KbGLQsm+?RA z+%s!dUzEWa%kd3tgN$*cp{Q6{e^Kt zuvKmed4y_-Eh0G2p=}vweR#5|CbxT(0}H@#bTK4}f-lMi2Z=U5Cf+FDu7>Zg%*?9w-81QC3re(@Mf@P<5vgDL&QE zZv6_%Lv7prVDo2W+{ML=l&$-GxEF5x;N;JUU+P&x$Ynwn8*K%C_K=$9_t4WNl@jxa zZRjpcEie^8ub3@>>kMq$$x9XtRu*WFT38EqZK`wWznr(`uB2r%jPY zg4$J4B?@be0r#j)>?EzqXb|5ABc>>~PPK-?fw1SF_jzke37If6e#Qd#JWQl?*a^>M_((eK{OSlPaU;+Zhd^3vPj{sBV0Z77l}Akdgk{YRH8uooQThZ7?DT;l7mfOA&!}LoKU5vP?8lvr@X9iM_O0kL zIeHy~%vuq7&DcTEsZfqGu_&>Pb@MHICSVBZLP`FzJU9Gv-fAR`Awr8(Cj3}za+kO&vZlHf}&Za1DT$(+?})hpUh%x*%CMAf0_durW2*?0kVbTje~K1Bq7Pf(A( zxjhBr)(?s{Hv|FFX4UsxG#khkUR)aQkEAe&79u1Xrx_?kvH8>25jDy-Q)J>5CkBE) zoyU?6*`e>2Nm=@qfuZbX=vK}<-w0MMRS(49#+)E%pj$m)y{dff(NNUbR-cNxcYLn3}^zJO2 zT8gSyH+I>EWr)o{*lc4Kg16#O8%>#sEUYK09!7S1GlF4-gs8d0)aR?7y6K3Vg8MrSq9t93b9J-ml1P9BZo=k9T zt;LX@t3}uxfe2^j3=4aLV3iK&kbnw{h~Adf)qx8YE|JXLH1&w0H6e#1 zQ9ra99!*hmHcnoMQIe^qL)Ohhz@Rk=K_?1(RAcudime+Uc{|sEEzJI@YSjZ zLMOuq0*9-)G*?rFQh-ei2N(1WC6%_|Ue1Rpl#opri4j@!%bcG|E=Yy|pKWuMfCn&C z%HyV15)Q$0=j;!LJpF_6)w3Yqgn6A^;H^S zw5LIPmiQ%h_#Qhp^$w3|w!kG-k-7>h8z|$STOV7J(aA&u;rwvy>H|mQxO-H-AAQf< z6%$lw@7OMv5ekMNZB@uWSy&4azra^V7K^>a-LX~|DvlK}eiRT}FvcawmWyOVeCGrh z6-n#04_zhzLP3MkrZS6))QKox$tL7NPf<#ZHT`rmX87h}yp{%^1;s->?VK8M^3f+_ z!h58igBaC>dB8M1hcDy+Sv%LVBbT(`RzTtdC;z!Rp2-mTQnb6cz1)M0OI|pGx#{!` z+?d8d$vZrGx_s{K$>pEnkX>EZKG-ZDVAh`!jh$Z|}0p}lmp@i{Ylg(2F+2cp7e z*dkP0a{}~i9_sglq7)hgx`HtnT?!ZelNs4FE4=DU?G-_USOr_7?)>y+01t8@Uh86{dB+E)e-B^L_0e}W=Lqr z(87?L#f3b9;Uz7_HyLPP^#>BY6|j%8qK6Z;mCdPbP&yqQ_73A@ z>pt;)IWnz5#;%&M{A%o=ty?_ViD6EjJ3h}3f)(LIP{`9!!Q5 zwKLiWa&COUC>dVXR(lrmPxMEb6$#oCa()P?mm8rjaKW%M5Jo$xV#mUS{wtoVNXN6Ra~oLw5#* zpj5FSv{+gN3eB3*BW|_FU}yWUhu~-nqeVVgmH8#>Fa?mRL}p+^RBU#dJXfmCnH10B zW$1;^3#u#FBO~G*V(p}HYVsS}gnuyrYsZ*A{ceYW;sp-h)L5nVXx40b)2Ng9P28js zkX=1mOGr!LTYYu={i!dd^T4<|A)S!zz1sU&g=aq^Cec{?wFZ5=dr24JTb|~jP{vjX zpW67N4_SWE#`d(9@z<&gd*Z2+hnOuII~pB zw&8aaDLlnwnjRhkSX|;K1<;6@pT5`m!dM<@$l2D3gl0Tlq!%F#;7FT@Do*i0<5jZm z?0xH#r`KxT1wW&*5zPLKqDOc|)olu&I~FYOR#OdL&8=$=pP=@UfIa1uJ*6@(3gCSu zrHqdz6-`iI{xDhyPHo!rQw0pphpWyDOc3M#L+v#WC&oA`_hp1sux3-x;HNbRnSP2M zOg7>{yPy^+KY}e8yJFgvQRM`569Eir6Lds0{>YG#x!tys@a8W+^}k(+uu$5i({dzA z2gj%c+RDcLI9|xrzL!OadHU3bhMnf7cK#Jskg7ZmbnVPL&k|$x!xNtVs+oh?MB`3F zOb?ENw8K|M@UjqtJ@Eyqt>XNM&6|?(0YippT6Gv5?j6GWMoEP&JLEau*_$H}iNb*c z7$JP69Lyo)FVeA#S$oD_`mA<*SN)6(@**mzKsf$oNy!5kN&--w-A9@w$C+V!p8@av zFfJY3Qz_}45{j#aV;`9l`&?0XCz?=Jq!3kyqliGliBc4<1?s$*Dey|wJrxCu&I`DF zr89i3Uj|Cwdh0sv);CcAs8Vf@+;;@^2 zgw)mQv-;39Z%Zp_6$(a>U5_7L0(eq|acc1xC9Fz}>L6=D@K>&Puw4-27n;{Ms^Ikv z&!@ZnQ+1SOtu5vyD`Fh*d6{YLK&St;v~Ex2?57MRZ&4Y&Zl`|NBUcSfg9WqnnF_xkPXu*QYE_lI!r>vEjvXJ zt*t^(!y(n#X$0j5xy(lS@{QBumW#9e)oJ3jwG%aAf<(A(e|Z(vCyx$0HONjww~0>Z zz@12EUfU^l!e|5o^>a}%HcR`HGGye$jm>4-Sy#ePN!wnjQx2{Qh)Rgy%+%0LL>=Y6 z()a7Z%xA<%M$SgtFxM4pKS+Car#~;p8TwI7b$n)srOOQ8T7)Sb7lN_{PmEqJBvj#+ z{X%@H;i?5RNTrM6qO1l<;K~!AoSiIxglXvifB}9(isEmB3v$8;eXysNHiM>@kESQ- zSBHgVqH+sVDbWhNBP<1HRFM(4hg@*)3sZ4)klGQ^m$tz+gaDEzeThxHhr|mPGV@2C z7yo6o*uM%3xTFM_*Ytsz9}z;H*VSGg;@QO(_L3;Bn535mi6oP>^%j4>X$52=TN>*nP!@zA+P}kfnsJHGYEzKtibOic;WcX(hJty_1O-Xp=WDeGa`r-5X{qrwQ>C>R0+0kRcIj80u!gxjy z)(ul2{7_{JAk`M1ITVfjAYc@tEBEZOh!USOo*IWgEszXSI*Yi9f$)Da42?^N& zFE7kOit}B9x#PrekmbW<7SD%b3L=`Qhe%!@UNI6qeqG?q&iV!%7cNYtCeTc>-HlEE3Aw<*bMz-|CwqJ6!g3H+`;|^_e zbsx5fveqGU`>b`sfYK&BPm;w2G@+KFL9c63P}k7hVCKQ~(m%e4&L)kIiIthzWy=WWwRclI3Gb*hE@M4LoH_*(85T@ir6eVgQVG zexWJfqw<(d??<5$ss@U6hWe}%5eDr+!;G+_o$i*^ z{cLfNMo(3La_mEd%9T<7>e^fdGB`$MIU^IE#5Zlv2lp956Q8dc&R-IA{p_%pD1Iem zghHWKMWU}QRK)fYD;%;grpEiJ7<%?AlXz{Mud~UZlk=aAq+9s^`e-}q?^3!*GvWkr7E%8+Y-q1z{$7ivWjPIwK2nfgH{25m(B1~HB9@Yw? zUhk5R>C#ijF)x8T@I@^t7Yz+lGOkT#qlmGzm8^WTq(6Yj2aRW5!M-YF=pdt5Bq4Hs z3!Do`t>u7ux)eH!uVz*uX;1D+DrIN42`Xt2K8)v*@V2?fm6jPeU zSS*rQAR0Fx@_uPz4f`bgWZ9AkJA2HnjpdS99!K&Zskz?M@T7}$*N+7Fy$@&@GB_vi zZYi}o4#sH%HCOsbAHUDWFBd@dV*H>;Idx{m6};uY5V$4AtjI97_xGME#GDGRDC2Zx zI9e>vbOC^eGEXV?53DP?RW`eY$jxq*lLXNY3e_wT7L9}PcP*#c&qn~F%(QSAH}*cg z%Xl*L*_IaBwf!*yTj%5h6O#eRN_mX7He4{m?+H&lbH=8{k|@MLH@A66fJCn^LcUMv ziWDhJP+#XggW3XUrt1wNGe}_~6)rfvz_;NvUH8H8Mt!fpA#4VIHOwinfnLZfzH%nN z5_v$>Dk$`T6sR8J(G+&mTetage35JJq#htQ5lA+w`h|dHQLDr=m0(m=^e8ezcJ?fv zy%64vnJ>skR!1=fH%AE_N#a&!*`k_ne*D3l1qdWyay>L(CEZ$nAb+u1s%GNEEr+iC z;1Qf^28BM2sBU>{B51&%MrHWnsLPK#&-fuHE-qEuFjS-=587B!pY@%bh|OUUHB0cc z4e7!x_0VHKYY54+e4xqPJ+I8(YGU^o7 ziW6A9XbUdGG&K=8GY*4^mMN|uU_gPD>|zS9yI|Y+e4;+Fb>`} zirp(BGD9v$%9S$yR@xk7Wp&cN1J=j*l_A7IMk@+kY>L6eu1d-C%}08&iNz~AUYCW^xbu*Ke zNmsY+!BP{au)DpNlJ|GNhti3Z#|m8w?y8TucaNV--*@AEw0I3a)fKd-YpKAF@rUn~ zrn_8qFZPoIra6?O)+QVCk zkR57ga3&}#l2SGV;WJkWut&+VAp{})3asNRy=C~SfalqWhX5vCQd+8LshtFp=u4@+ ztx#ua=&RDyw@xlx#KOK7u-5Q*c*;1MYw}ca@_y_K2<+G!{OSwwWA@OmWCY{FC1ZJW z`xHLo^nSTJkGXup82cnyk$WGaQuecC3M2PqFrh;ga#{Legmo9Y9J((r*LdQfn4wej z!ZTbs{3cVA#5BKXdip7Ef(Ms*jTO3&lIsscI7nCzV}^94>R-Da*V;H+ z=VMy^`L`Z4lFv>b%pBz@IbCG6x*cwaBr5z5kNCO99bFYRU9YK9Wv+Hy6{gHOZ~3)I zJ16hoy?glZt~?`Xbz~?Ut!BuA6AXZ=m5-oFe-eg~yUa3MJ{sLS8{e*wddvP4UaD&| zr{1z^MrL%(#!^#BcgU?tb48w{O&)KrX&-BYdE_<)O=4eZO(6F3G|gTkKpk_qs7$xC z@qn-UoN#^XtU%QMt9T`QcU{yem05}?kxk(NCF%OQB+vcle(!~!HQ|)aEc|LqR5<|| z=z~X6<$OwhVWeXEK63Y~@H1J9gnsmv*Ua-jNsc#sr-w<7N$h3dQ-{Q0p*SmXfSI>G zG-zG9CRNvn%9}CEihT3>gEOyn=0rr`U*nQ)^`Sh&b;_`ySj7rr1YJLNaTVL^**qV-xKLX~2a z>3u790%h#vy2gi1U~@((J~yohL)5Y#pR>)ia(tS&#QFYpEx3+!jcmpK3XaF`z@LiVOw%?J0*a^D=cDKGNfB?#Z&9Au1F zrh;eQo8b@~OfV zBHaM~laI6zKyz85EAZ$Q$d`?_{R?u9gZ8tAMEo)s7irfTCp${`lcfj&>;?owTzkpA@pK!2uX}4ERLli zkpZ;m1?0fYi0q7{+>5cA75a9sv+(+w&uS;+%PpJwM7*=e0s}=_Bx2@C1)8rU_tQ)a z8aW30Ew8FVpNsEW|M21$+^H*}`~3rT5H+MP#3jQVa*St)r}x|}?>T0KuBuw(RMari zXVOcGMc{`G9vs5E>+!lIr3uW4s4y{tG5hi8a5(`jM!qWa3F)Q2jk@ z_h@KVi&O{?eCtmW&`H}6Ic!>f`q{0-VUk`T8CWw06r+s$CL7sW&rq0{5VW;9SYHu4 zwL>Ba9ww9Vss)w^=fSQ|9b`B3{9v4J+`Id>I(!J3SW=VB-P23PqL+W-mf+#he1CVI zX%Qey%M6OrO+C~D14Gldemg~>qo}|KaI|MKHFq=vGI`oNy`8cE0}~MTbTS3l0$oYX zfR@${g5>94y2(kc%>~J|ITcwHoy37w)-v88pt`q`2Ef}Ez-vw}EQBE7$@fNJ4|Fvp z^|ZHhaN+Y5B>#h#@9p|`Gc!5q9}rhtL2?~M6;g3W5RjCEiGzuSQPR`eosC=wfm8rw zZo#J}A@vu<+npe}m8+{0A2YLuhX<1fJCh^Gl9`p4mzSA^jhT&&@eRS~;^p9K>dENf zLh+m8PYwy73jk#8C~0)XdS%Rgj$gt)KKS^0!`qq~}}XUkZNT|3UBKYR)YC zcEj;Do;Lt98w(2$BMTcN8!z+U<==W075^#i;PRIj-~7q!Y3jtx%EZEKZ~t!+F0PX9 z|I+tgO1Nme9cE!x1G+f6fdD{Bcc6nS#ov`W*}1v=U8kE1@ORT6cH5a-Fuxh~hvvV_ zNXsg!{8Q$)8!fHvo&J#cjs82*{O#T9FK;-xf$aXkm;;!Bc0l_#LtNgNS^o|1YHjha z0R7u|e)s$@hP%-QTVHO=bQ@1>m*- zuyAm2F`BZonlf^5aj-J-@Nk$ivH`eR*-UwWKz5Elt@#}XK2a4}L2@=GmOse2< zb+vE=*$a{@SUb3R{;Na7+8(IxYWmx0tXy2|teot;+^oFZT)gb8{{m?NK`w7e{+pAP zg^7*rj~;UXpVS+p>07c{+nZVfnVlRg|LFJ~7QVN^ygAnNcWt~e|Iz+77Cvzh(A3ot zq~YjjCrJL=GSc6af0Pudz+c6}r{D5Te5Qau-S1-R4mAHG1aE%)vkPEl>R<_cn{EFp zwSTl*{}*Y@3gEEd=Ca^sWaE0vWe!%ew=^~bvM`zhIathDEx5SN*#ZB~?&4_S>R}23 zidw$qz+0T(O6!j}lhXc?eRThh_OJrJ^M6po8})yb z{Ez(mA9wx7UH>Bw{Exu@$*%vn>wn~d{}K2<+4cXMyAb}hV*qq`dvNu5+Yg}Z@(Xy| zOMo$xmzDtg_4_x!voz(c1>Q+U*98m=5%c#yI9S$4+_y$pS6M|#*gbd@L?rfCuJCX$ zFj6pC2~iEt<&!lJPr`-Hi_3F6X1!acrDQ4({k~3u58q)R!!szMAi>4t+d`8Qb1#xX zm}e7;4j6Jw;9~G5GFB*qKbY>x3G|a0b+yic+CZNi-gA;p3}@ z?3Q~UH>?ZCGgu3|>*`n};ese-lmGaeUCO6Ln3$M=gxMD%@nAdq)&o^FIWiB!)6iUK}Rzo9^)pZ?DFf0bt;uhqQlm=cQ6lb090i znbqU6YD(75nR4KRqluX$mj44VoB1wIir49aRIpQt5FUO!lM^$dA3RWrI^iD(OEpT2 zg2h9z(z#7ksDtD4gaB$tw7<+wo-9Mn`a$-$dpx{AnZHb@{8zI%7zRyXB-&SK-{Jsw zRWi8I;*w$yfo`*_N2)g_KN)RMg=2P|}> zbiYc(dF5%$eTE(B`+vDp``_ECgwGuqu)Ig`o}B1P-Tax8g}P4f`0=!`{@`Yn`x?XO z%LO(91H9!9_e35GGp*$h?nz3)^E_r(TFV=qTiQ!sQ?KF93Te@R__MHULOkC_S33E| zXrUjQWhR=gI#`ARemAuHC;oy2_eF{`rUAnN;R&8XFp|AJ?aGkHK7?N`k&I*5ogK3$ zdprG(+&J<;BzRcRM88%a=lFa(_P5?toM$SL?CDym?|`8np5MED9_brR!qiRX$B$U| zbU4H6462l#GEtqhBJ}Pr1zElgD<|!FPL=J*XEYM&SbB-J-()XncQNH$#&qd`?xo)Q z{)-VU24*n5bo#{vZ)F>3)sE?Xu9%rZ;rjN@OpHTGLvy-6CrC=U1hRLg^2}6Up7ZA> z7#P*aQq`9iCVw?usjXp#DsmW#=b9I?T28`V9OS$ifKg(`NCLKDuPw6lqzyIxv<9(W zN4S|f1nkp_G9rv4WA2EvGP7xcv#td?9W}lE+m|v%UDb&WR|T)lTACJ2I5Rx$2DO*I z`KBh8K;)A@^j{srA-7o}c}*>QF)I>{TwSt1yqB}! zS8Zfi$?kB|*KAjZQ%DH!=Hh|-+Fp@MEhU%Xo_H;C{@RL^^$mF4T{ZraFu<-t8qn#4 z|3N8ZVy=4Fb2B)*4Ae49f&$@m9~u@bJF=BuNwlV0v$MhH49-3EInXsFZ858IJ&k!5 znfffVIoehZ8}yigH$KL+C8G_wn2+6WVK@LB zoYN7sfbk~dIk5Sq(rYYYwaV{<6{B{ww7%jx885hCwfQP(+va`+;gIb`W=t#`p(&~U zwVvnu!dy?L)hI5o;c^ABd-U57LZ8^PPB-gF)<6K`GlC;0A(?ynGUG&ayy4>N*kD+3 z6)}4VmSk}ez0{~d^^5OhG3DXSy!Xd*lrpR^$9EI?{3pYH;bZlvhEj-W(VX{n)$P$F z6CJqx2n)GJlTzxbB2M-*9KG@rdfC}3vTx4GE>YDJZug~8n9KQ@@9r{+<36^(`BRmhzfh%6wI#Sb{2g#?@NM< zQ&gnwAI{E6lLUd-h7(9o{i<-#E$|p6&|a!eYF`|7;}~Q}MB5v0Z?xD#k{rj|GoJ5W z;?@M?V%>|JH$mim7;h%d?_ynP;`4>!?i_;|x>fthB*bVDRMHP#u z&4()otx%rPMLw;I1dS*uz~T1^k&97mSV>AIR&j&N`F7L6U>gbJh&*rUBziZ=*6z8x6COmDZvGOqE%?2#+cJy?~O4jA|Vv>GZwt{cd z)zA^MomOld4y!fh+5z4?FF$Uiq|7uPF0f^L(adQSErYT%2_gl#7Qc`eqo<5EmXqekj9Jlv zB8T(~E>@U8;c1g?z}5XHu|lB}8h5$D-jX@>jAY6Cd`x+sSjAGB6_ft51FIMqI2*ke zfg^FDJ~46dD@84}TMNEVq6YOBPPyDEfI1A({G5gafs{0)&dl``FG~%y+6;tK#}J}5BjJWKGx+c|(u&Jgb@UOC28^JZS!H*zj;XQR@7Zd^y8to)SO+={+1DCT9@ei6O@QQ0dY z-_Bi%OgH{rSM%eP72H`)dvuJnvLq(H7#wvrk&c`9QNQ@(P|?9#003I9O%f1o+lzAw zExpmkF*9hFg>bl*vOU#O^+!na5q{?Q<2(4(HmR~aa?lOcl*MWwh5EP5;s~1}$1Lm9#aTH_~ zxzbWgMae;I;ESawX#cWtDJT&dZfI$eYJDK&fb<-Z%P3MaBNyJQpv(|z{UGFHDXtek z6D%D!ivdp>e(l{+-)l}~=otS25+cLOSq0|~9V=KYC9YQosui2Uvh9QoKUN$#t?R&b zaQmg*c23}M*q#nsrZ@uu=bgxBE#lR>{1t)!z_=!l$2n=d`fiY~7;lf6ykD;J5b z6yj+TscAuy14{uInIgrURc{%s>u_HiKs9=t>x2(-0$n(F(-%C^g2hzbwMkNZ2bYmn z#F9gzrdQ#e(@~Zkw({7DSfs~pVPm=)ggXb(ZYiwM8`CaMOxJkWnbEgq!oeDn zQEnK?sQpL#>fuNmeB3xVvbqD;clsE-_*bNXYPRGweg1uHw2!T5Si$`A>2-S@*Ivzc zq|Dl<16ACh=MMRH``7pJsIK)B3*O(n;q-!u9Rf~Gr6_?;hefTYkO=U=p+li?LaKvmKX| zON0kl(8dh0Xu&@FMpELA{0SQ8Ti>0=>E4<9x9#Fx*+s3g9E&~q5!+$Y6I7sH7>g0R~0rTRJY=?5T(HVc*)%C#ZXL$r|PEC2$?04*W6tnTE>Xv7O z8j((m->pUoV_XY_IrlJS$n0#DAG5*Km6eD;XvZU`3 zuAgG-c9j-@XXg_scAVJvyVtdXp}LkoW@pqNpT3pWAGp5wo&n9Ni)T*nS%erZ%g9Y+ zf4mObIz@y~>evhTIk5}YqXm3Ez;59np<*V3*3`su%n`8j8`D}ZQk^O|T|2B4}6U(N-q9h*II`Gd4o*|<09jQX3_naSo?_}I6v?B&nR z?Bnf}2r^$4kCWGA))NNM%6w)FaX&_{Wv$2Ce_A^{h3dSqf8R0CIb;nf=sb#}yzWbQ26mRG!$i$a`q7XzOvRRg=fk(e9$AcJk{guaW( zDeD!{@995Ju%s#LTF6i_oB} zK3nV57bM5&i2l7FBH~oc9NM5?lC9GxhuadyH2V1Q7oE@_=5THj?c{fo1Z!2frk&F( zsv)}Z`^(F%#PV(43vouP&N!dnq?s36kaJ+=zzBbT)JB4#=r(kvI+KB`TM0wF#If@Do@7m5l&fk$b?5rcTLl6-l1x-P_)^vlS+;ZK|2f z>&c>v!MpI0Y2a&fJm=%Ob#wYfWxU^Vo6s<~I7|^!W3nIBuW{FWJy&e&^e8BSMv1Gi zpTDn$rd8;Dvj8o!ObW z!-Mm^Y(%Dg4}N2_ys1I$p$W-aS`O4Z&~xxunX~(a?=5jj@eWI;6GWF&q7%dDy+@ab zh`MT+iLNO;J!lv-H@W{f_`+<)mDOf8x9#ikB=>%G4eCXRi7|6Ha4Muft0&}nBi}Fo z=SOXFPO^&%)fb!ChH$wqHZL+%ZtaWts;Lw+mq0WfSD3DbQ|p?{HZYH#G2@kZ6i(9b zgfExD*$=aypW(?K=8pIuw>F6L7ldhT_kY2tDQeYxm?@vx!t(%v&U$CCAdPHB9{ zL%P+h_4~uO9Z5J+VXBnX0gl(Yt;*G=OXn;<$ULiGB;E>xN8@H)trv(Hm>6Z(?Vc?l zSVd9PZsDe&R=vuRiLbl&^ffeYo^~Hat$Zzy^_cLuL+mTNdbw#Bik7y?i-uGJX;2(? z(yOPY_f9SK)VOFMLIhO0g5o%zt*vZL_R69pLP_ysE}yTsA5|Z1UqF*KcTEc*m!(ER zTgM;avxC0v`Jt{cakcjT(dQ>#nHf)K=}{RKSDk{jPTM6kGF-ZkpkDJX9#a&fylno_ z-0hY)Wwz3`Pz;~iU_?ni zZYNEww(Zhk+*&LP_^leXq;KaaR?+gI2K8+ZyI&p6tl0_qCtgdZC0gU-pSHYy7dl(| z5+8{#UQ7GpIV6V<>+?9WiM*4=K&gxQkOx_NonvpSdh4z5xj-IE{34`$4DZIL-F`){ ztMMmuRj$AX_`7%Spn!^+tL;C%jB3{VV>?*S-w#ykDPK&S25jD9Mm+Q#9KI}WBHui% zzC2CCiNBuy=d0`c?Vj`h3lR>q6XaK`de4}#LFa@fp^X)ZoX>{bP6jSbSyz)Oy| zBs_cX6JNVyu$*4%X)?7DY4zTsGfBVH z_$$fA`nWyNcFD*i<9w}}e8D4DYN-X{;?8MJ#i_WzB3a4Z9qeCuSRO}QIy&5)2_a~2ab=~a8Q-f9A=vJP z?I~UYL>;=Vc05kKSgp7yOwySch`kqsYvI&#e!goq_^2x4Y{Rwa;QR6XZC#LYE!z|k z-K@miyZ%0ta}Y%3wQc2gf7vO>d^uk*p;L8NFi362diMPm;#cP}uw)-=TU_Pa+}9LG zM++B4-VrJGvFqVY9Q*{$)cUuKYRTmp`1DEb1O^kLH*aITZwj@;*?Z8WO`A3R$6gfT z_jv<1Eq!d9y?Ef=!N~ag-0`v-128rsy5E;oTNql{%A%6_VEoU^Jm1#F=|8-{qUHrq z0WfFFu0Ml8JN68>dUW=XpmdCc6_$QNh~r+V@ap;$tGMutmy|lR6$_z94*vRZXTdd3 zXyORKLX=L+S9gVj>R!F)_V+QzU|_yvt*g|wygF*6hSqe&bL z#{%rUvLYid+fU5Sa+@+RAq7{PZms#PB3P%Urz8b-BufRrv$uyD1O>HX^qdmfzjHD-CagcX}2BSKS1{6-6M*;pJt@XkVq)a;~)J7 zI&ay>%{KhH{2BCdU6h!=C556(h~xAe5*3NXFIqGua2vp*7bchL~t-l=ce0ZotKv@Eb)+FHXx z)`fK0e{r++B?lVSmQF69lZ1T&tJjJBypBR$vR?qYyK?>1JK#kzHD!HixRk<#b#F)8aQDbgt%ZbtmnX--+fb{n4S>+9B4KM5KKaRx2n8nu7jkcbj z@ZOSNh*R$VqAudzhS4S#YDA*ob8Se}i0(VfolAFHM)U&oXqdwbDbaWE4m#VPc0_zrM4(!ZP0H*m@t~liU>JDV=ll<&HB$cFCwv{?B*OFof<~-! zPzqxVJHIMMBjMwI64P{wG6PQOz>vIQ(ZqfrL$eg&Zm4d~9iVzf70lq=rC2o#MN~$4 zR5!8Qe5gQ)Ge5iYfkQ~kz~64C0Q$PT0x6GU1@!8F??Y^8MTp5dpw|)$2SSG>erjW;CjjktJuXg)pmP|d+~=n%Z4 zu&JWBx+b9%J$nPf+x{cE3gCewP0o@4fHC`heGyx@G-ba4nIylYB9t@j@bIxn2h-DL zFb=NAhC|&>8K|cP4&7qzFso(4mdU$3BQkGSGPV%*9?G9nP9`qdjsw7g@6~t>MQs95 zhFnxM4j(a*nB#bRa(T7NaAJ`2=@Hj}gAse(T*thS7K7qUi<~|na!tz32%oSi?dWtb z3j@}roa+!3Wmef)Rqrj&N^0D;Gz`ySc3X2oWsV%q-!_q>@c>L;gqXMIuF)W1#K1p^ zu?W${WOXq;nVFhJGx<+QXPt)LBJlg*M|gwbqd1SnB6=Psuaq4*?0tw>H}|@;dI~o3 zHbd{Qd6(S_C00lJB@!O*QNx3~aPF|4VB-6`u{KwEWyMl!U=;+`H77o|L$#sC^y3kGX-&*vi8M zh@1E)knb4Y3M;Dogx}e-Y@ZUF3?$c|st-3*x?5k_6`X-K-{#X^bE1n7j(F{wf|b+z z_46d3+B+ggw*}_~ub3Va->ILaG^Nf}<=&pgs(nZ8@FG`p4e-OCT<>o$tR(T$Hw$9K z;G|0SrdJkY-a}28lC++_AUmFwaK&mQT!rgwlMWhBe|lxl}^ z8UC<*uI3R+l`P=^0T*miZKfCaPz+T`bnbKKeE+*^D~P7o|o83Y@y| zL*%4Tl`*Ag-!!~o4Ei7U))u)%XH?gnV&T0cb+CvC;yLKGQ5$1u*#D1SL1uz zYvD%0!wOs7an%#_bHdJBczZTA-gw}-o|Oh2uWG*73^w~dI=*dH?4mg2bS8)C7J3$M zKj<k#2f1t>uz68&F{y=7Qd+xG>EfFO-@BS=bjr&3ZPAxMXGcZZa8Np~Y1 z(%s$N-Q5j$anA4jpXc6B_k8kfc=uj=tvSaWW6ZT)ppw-d&Ma;x+ZZBssxo&msx(ib z+?yUtq@;+wMh!Ra24#^5F}@^)w^i#G>J46179N{zoThLampqWXrwzS+cvO5%ZfaP( z<{;)^sry8>#gmf~1Myb+qoU%GK%H-OvYDZvREX8?uYh2gAySGbA^tBIZNlNYvRiQ# z$5)sT#@uh}zIO++qYk2 zaUC>mxrvXmu9!(BXfg7!?0rZa>JF0V*TJisnq?117OLZAX+jGm^tIn{8bX+m6|KKi z3~=y@F)qqBE}z#kF5W)4j$%$+RDFGWrlo{|b|L!pP=et4YSdp#dzH++eEqd8m7_5K zh3NVhgrBHXJA#Pn-2&4G+HUgJ$vOo&J;#q%=ged?-v~*0p)b8^S|#47hSk`P>lQ)u5aiESUwE=Uer=M3TZw5$hM_)p=)(jgK0vKjOT20pVg;vu8h zNZ^#l=og_>uE^0C=!B2_55n#FRM5h&&c@2&4DqO)`6!}%HJb1LX4BODG>@4hbbOmM zC#M#f;BC`_OMK1W7Sm&aT$sy+w{cxTzd6+#lxI`b%(IE9%wojPVd0u|_C${rlJpDp z=O2~K5fR;oI%}HOp{zyrMI6tvd@)N|!lW zwkd~Rlf=bv_;npAxvQ&mWfThM=!H3d+hjuvIVsS!_{ufoD@al(T9(>A>41U3D@05Y zh5P!~n-Cvp*hX(YAM~%d5pkk<=g>|R2;7aKLpML){xl6rjxD&h?0#ytI^O7f*k0(b z`7zIOoKRxVzIzFivl+Y=_>DO2!@+h?_BP7v8xjF~RmivLovH`2<&cj;47gL!3M7np zh=skl!x{!G5U5DGl9dDo*_o^fmP}*-ExxnLYHaY&(GkE)fJ^b zWRv)>?y#dYt^<$jqHIr&oo@58x9E^j8SCW-ObwIr#2!tlN%((uEdt{(m0%P}8S=9`6b*8}CoOXCI> zPN&v+t$U|$b{i(u%5Ei!wPeqC5QXTVgS#bnbpJP1JL% zoKI!ev=^ke8UMEzz{>{RbH~#wEtXacewb*fD-77S*%i?iL+YIcm;SX)8?HwA;4G!GP76vtwQZTY9nR!TJ<0MW88+jXcP)%o^5+n=e1dsZwZg;*s0)~1sVdLHLNiSUvVIub&ZWI5Ar*3OnU?)qGIBui^nPI=A2KX z!@lwJ9_YazycnuWk2$g$ubDYsO9(jMIou~tGjg@Nvlh+T9>cdpA6F0-USB$oDa)=1 zUCXkCY4E=2Zc~fqiP0jH@+~1Q$QaqcZ^`4ZoScbwB-PIOfq6pu6MG-|Z1Fa=8y`MA zH9UA!OV3TW6ZTsYhU3EaK8SX&CuIbv@L0Q}ZTw#&N^Xblf9sVwS zO|AQYRQ?@zjnUcdLg_8_)bwwg$t>T(qS^MqHZ)@%e69)mpY_;oUc*SX%#;qSfAsN> z4CBl~6c?H|j8lr2IxC~F&t@X%$Xt8cjHHa&9c1evEXX=`{t~!5tRR)+)7_!SQ`nOtNBUFkW9I-!>4PkY<$-8LGZyPYFx~Ey)ekJAwL+pAY{uc z<=Tyrt=6SBTkkE+0(~I!d1=+u$nNfY4!R(G(5_WHW$mzZe{8{WB#Da?@VhI{v0=V_ zNWMoEP7~ugTt*5MPOOM>iE+hkob+Qr)9KnlBU)%q`Pp%C%?THh;+cp~LARkVBIYcN zhSeCMAuCXzKe*8qo@hczuk~(+uZWGB0=hmS)O!B!=0lkdO}5eP#r-0$t?M;c!3LFJ zQFnlhT#d<|wKEh^&Q{1)yl%ZAj;-}^2E*I0nNs}(onFPF9~wMT9XZER2J9-7BHi>5 zaN&AygoTDKGtA`_$+P~r{#bK`C)_3bUKnTRjQn@%EaWzJZF*msSqBn%eVL{iIXPw8 ziv6#TRr*8>Z}j zej)4d&HQXgu#;oZ(tF9G^kw9G`<}$P^`={6<(mir7*=-$a

P+@X4D=9*Xp7P}&z?ZTCA44%Ssr%Wx=yEjitO~eb^BnY`1I-%t0?H+$)NA&b0sHQW1Y?=U%vdyyRdxSepQ#%+Xb9~8~8kNkCU zw8tk&7=F+q(sW%<1 zu&y0H9PQxM6qMWcBy4t39Ba+`SuU=wt#5s1m8JBn*cHBT%@CGkJ!GFU-omihjERmg z&-4TCPL387UQlh>Gbt*Vx3MS1io)%bQy+t&m`O$*BtW>>nl>!GDTuuuVqaxDjjp6i zu($v2;JlR90CCW}k@tIj*e|Ti^ju$rbIP$TtJTxG*(r5dEl19nx8hT2PHFyd0V)qi zBdV--usewNy9fJvB16h^d~UAiEBJZF!QblldWD7?f+3gkJQBC(L(`$U@J&s3iw%|q zVdd%mIJRjJFtx@UIg=*z;dm!|4`I~_^N(RdLA_$AS1+=yty7L;3Y3$u~mjVi~24P;xxD^YxGWr=6sykhv^7*^{%a zfk{@ZNLOc%-X*%I;RPIW0y7`QSjB&4d<^mVV|k4X8xDW#%tGhg$O_HJi9zUR8F%Pb zR0E?vAT_w{s0r(GKgTs3;e`hukq{@`T%XExr7#EMd@Hv}0SJ9Pk4!09V>qNLT9~3~ z<{U?h(-rG?DD$Hv`&ZAGSE`7jKOeN_KBp8eiR5}%8v0_UTQz`rwCUD{0Pe`w@#Wqj zFPQ{zrZJo)#*%D6ce4JM(TCZj#uf-y^0hvKvR~;CXZ_!o@ z>l<2{Jk-M4a`sHoe001Mj=!$LV@sz8eQ(h@w@fp$OA5DGUgmO zAH>}8l;cKFb-@QM|3B1T$%{yc9l{`h{?@9q-rd37x%spSbx~xU`oCArJE@yFGWHep z%%08Uno$`hmOU`g_=**39367qT&w_iu-Z3SJXd7-`Gp z*2@c#j~IJ&1pE7GY&$}4f2x~R(tc*pV%#urb>_#PGp^AYux&cOQcX%?t}iNyCR6-j zHDwrj`S(Qp@s+8tP)Qfq7Sx_WwXr+!`;xW1;*e9GFdm1sRkCvP;udyxd|IZ3r6=hx zWJ<}bWJzvV;FHW4(}}$%K5!ZIY;Q=lk?UQ!hJOpjSH#cf(yvcrs=jgWS;}N-MGMjS zWqe>%v|3t!uO3~umFBOzC`~I)^KLn^$7ZtLDRUqC4>w=BR`^FK!Z^7eC8>s`ML|0; zJ{x(ll{2LBva(2eSz=Xnx|s~7A<4e2^gudCDE<$ybv={uVBeC@2k82H9=Q7j+F@MD z)aAkT%gv7kCrN`EP-!Dt**PW2q2ivUBQvua{XZw(ZhS|(nQZ0Y+S|`u;t1?TI8>)W8=5Z+v+r2Q2G&v`yBiXD;;>xY90(&gi#>4Al}XDY%O zg=I}{eASc2($O)e$@_Lp40uE(`)k(JDvTN;Utw=w^hb45;+?F5l0?i}-Q7#XllH)n zH`1GN1WyKXSXfE)tr^qyTtitIn1k|5|F7msCzR@_Z_-=imP>qUDVgEV3 zhf?N|c7CC;ljhGG%)9hGfCf!3c&RNFf4Pe|=tRi@DiaY4zEFbK%9e7;GxqU_C?}r4 z^sxB7+>W8;_1LLKBc}mXb|eNNxx{R+UDo;;%30JI#||7UBQ^YFa>#%zLt1)C&>anQxt4p;%!SF!pFokMi3~{;2&H@ER=Y<{Vq521P)>4G>9b%!_NgOc?KptG{Q7 z-WFDQl`#liG6oV)j_j<8DbZ&pj99Ixh+pRy`}P+v4O=0M$=ZgFU~E@WBecRp7VYAO zh1b>N3!;tSjMTyfyiR*n6zb>lY_88*%91$+KAoIu$E+$^PthJu4<^T*X`_6QFnA|n zp(hx!MyPQ#lFkyIHa?yyDx-R(csGst7Ed6h3C)eM$Bm7L-?hV>ah$7x%p_;YM=~Vk z+-h}f_a`@@g~o*)JFC*y@ZUl)d;x5UDQPWQIp0ED_n_cq23aC)DGG=1+JByobIvWc zt;t3GG5)hT&BpViO`JI33q}*i4=x+A;LVI_qBh!njqT4bf)9d+&H&j~A@(CT9_;}!Dj13E_ zVVXhA)YOTwVW!)gDb5$nDp_ITP;E;>?hSTDi2PaOR4q9vqU=p4%T((;L% z5*>1!nw3KR-)7tY*M?fs|KC@K=st=YBEG@AE$001GyDONr(w$^1~qmUuJnn|PVwLW zw`cc4mKHArY(<9gK25#C!4$lQWjJQVv2`AJ?w}<3-=|X*f$<#}2!D5f-`m%h@%QhA zTXTJdDNjH^z(4}qe(GHktMq-#@Fu~3yM*t4+uGZob>Um2<$nm{zoVj~qdOhW7^R|* z4QguQ_dx}&>pRqzUE8(m`&TFTkDSReFtD)e(H^n=zWtlRii&NkjE|3xHEQ&%(m~H2 zv{)bC2zhu2$mB+8F**(nsldGZZ}8N;Lql6bJjZ%tSrTzlIph5EwKkNEjg1G(&8hAF zD4A67mzS4_$jE04Hp6eJ}GbRR$-F!h@QWBx0`H35h=i$)8<2_bTa+D2wPd~lHc4&TnhYk}WjMKhEDiH~E ze!dQSqF4Hnhoa(-rr-RE2|4LT-+48iGf3(dWPEOX0A&u>k)`NQph8!<%hh8~+&w(p zoHa=8T(t}b&w8e1Vv4A$Vh;=o!sW6ibGbg+Y&ajv%**>lr&^`Oil@@#%C%~V!n9brr)!Kh#@=@no=t{k+8a59@6IvRma`se(hF*iMWi6s2s+U>$!A}O!8+L8DvVCq+cH2-UtZ` zLpnJ*W#!~pUoSeKhltibob|)`w->5bhvJ*ptg1IMGDAdUd006&5(RZy%b1%>I132B zDO57ygSV$MwDyR?uUH0bThnH##Dsm1UT>9gILiTAG}P zhv!M<<3}iOZ*LG1%mzaQ-@kufYy6p?pE15WvTJ)VQ|5hjW&c@HvbVQ)wI|~Jr%bt@ zty&G!s&87i`LDUE%;rTue};#HgTuhat}tKZ?h3~J=kNI;Qm4o@o97@h=+K z!dEP{T<6jnSgn%T0;V7yCq`3sHof&3*GK%hTn33-=5i=)W#U<&cF^TDGBJjDgN^2K zwFTI+KW6Ydg9;H5aplr^bpKLMPfv?AW%l|kNzI*sl5!g=Y<*qo;-O|<;(0-42!+eZ zEJXCZii!$INoHnd90Gz4Q+D0zc>yIN(4(>CmXMO_&?$4xda$>4*j`{w=bsd+1}O%Ls|f1=;TUlm!3ItusZx>#XuSiPVgo913>RnUDhrZ<_RwCECdu^2&}zeF>Mjc^yDXu92S z^7EhCnHviW58OOh2#^7a3@4SHNAtalyr9l6D9HT#_jdp~C1k1DJovjF4Aj)rwzjq- z)6-(#zvJEB-a^HF2leV@9e-<+=ht*(|=RO|$IWCDB88d!8X z-h7pp-#s`W!wXqEb;RK?Uohfx1vzqYb+u;6NkvPWRZ)SSEF%U|*1b8ks;cUS381_6 zS_j;PGoOTnL{?VT$lP4u{2>JZu(mc~43XCD^HJ~uty(PrRHCDO2lb<{FIjXpdn6EH zTpK373Vo87^K4R%;|M*{c5j7_F~B}oQVo%!+SLSi*>Y&UC*)5J>*)Ao-u!sw$mO@Uo zLiYD=bh#c|Tny=6Uj--%7GV9X0xnpoqwE+U}r+goG#;DY2W)ec~hl2nhZRNG}L;SY(2C z)YJh72c}?U#ARh;vCmlc^dx6`AFOXqR>$FMladGy?0G=k#0}~r6LNo2RmH~&^5s}^ zgaQ#GCI;(rbFoytC>EQbNYx@^|8;qhu71jgH-PVm?-4QV#DYNwElTwL)N7q%d4 z#l^+b8XJ?lxVA|N5pF4RR!Doa6rU_B&blSMWQ_Oaq^DsXPf1C?8FX z&CPSNvV1fj*04|Ctz=OdIOzu9(Z zUtzbeMC5iM_jK*?9P4&})#)7qs)siU|1S^}Bk3P`Z&ti{Z#SZdoi6+iUPWZdj{3l% zi%UuAEjPJ=hf>I<41f!q)*Ekvu;@t1$zMnHegegt#b784Bqpe=!s)0Wfd9znLNdDD z*^Z5k0q}sWFc{7OH5Qb_q@na!M{;s{Fq9JR01tmEkV3cV^<>cP_qY!r)vNAhg z81fRKd{ei>^b+(eFK4E&-9X#h+l%9}plokj=ZLeb!<&U4%*rz=GBRS?Nw;CLI#VzpRcwMC}O7a zd4~ZHaul3>D^tb+gbJ|2Q@b|V$D@0~sO4jW$GgkZX8EsQzhL+>>2`flRh87xNNI3P zwF=DmqNWB8?CF9}R?k1LvbSoXrVe-eA>jjxKoy9_5DaF@Ws9p(BMcQXb5xuPL%3vG zUO}M)BsG8PG1T?^*qE?|1%rH!RC;Y~yfUpHDk=ZM-UP{;F@x?3Iz_b!*Wg40jh5dF zI&-keQvJk(c^k9|i;YsH6xJR4k>exT9<_IZ^781ie3uy2%kC}>1Om6b?1_UjrtGZJ z@6iG}@O5R(Rlk4lo2xWAb#7Gic)WaJ+jAx*=~SOxk(VXFslu8?b5nNw&d$!f{JWI% zJq*yg{gUDu0|WVro11%N|B@=OZ8KJLXsOY~s#eW)S5os%e493P2-LAr){tZ#hq0xl zP*h0&cCSfea;%_;`1sxir*q{>V@v=6Oi>ilZO7M9QBfa7MPWt_FVr!)lVz||c}RWI znwtfd%f#2+o#_EjOP05W}De2;ULx(fY<`RiZHe-@h?@P+!=W&9+Q= zMaA-^&LsYqucPp+f0bF$yYMjYiA>hpVwr~of0Sg;~k$i)1?)B8xs z7euUvs0H6jD43biV*5KiUqSr}4b=yUORHY@SIEIgFpP*#8DNx%hzQ_)05A6%U$I#- z@$e7>3T!%4>IKLSARk?Um^8lv0$Mk%nE;otKVFgsgWZ`fAwJ(8&aJ75+W`k!0s{dq zi#N9Rt*yNY#YdopvMV~;26uTW-P-MbR=1n6750bUN#DQ!Q(Uay@$0QL%pX7P7rp}u z7ZnYS?!(P#t6&#nFie>1tB#Hi@U`Z68JU^8vlWyk)5YYZq>$3%zd}MfjVs40O}_Cz zUdV%6QPa}?#;u?iHh9o@ve!eGCD1_e^AeE@kW;YE?|0JK2zekqG}bS6PNkY8^Cfp@ zJoLh4(VwWFMKjGy98^$H(87Tk&yjA|uZT!Uz)PYfv*aV zEP6et!XH1zGipNu9fpX*=;;lM0@$Wdo&6zR1HYJv$Y`UBLtA@0NGvcDq@<*biG#s} zJXle^9f11>1P1DyZS(>)+7(7T+~js|xZK3o=zM8B%1;v}@Z{M0n_50&^914autJ&k zuhBS6!Q}VjBhkg`B$y*n=op$nG*=9oQrZ)7$(3T!G@id@hmfztSIp05_hIpV*A>G~ zbMb_<6ygSEK-Zf9)^~h8-Jg1+&4}m?Aaq4gtbS2OM@Oe|otU%B?)K4rK;Ncu7|M?F zOYTrHk5}5}!Cy!tX#KBn6O%3L{!x^&=B&$JbvSt*UVovsMHCe=v4UQ!PrnFLbV`|q zmE)mRGr6bblBv1OZ!0dN|MYO1JqAVEalJAmW)sU%b#TzFFr*9PQ?m}$qiy|C+4-Tr;Xw6z6&EDeQ2IZb;l{X|E*TVBvW~#j5 zrw3Y;Y;4gJ6AIJ=#ME%S9i4#Wo@OjC;QG+}pbEbs@wpj#NiX4tH_4AO$Rte`I&B$L ztu2ZM86g&*ysYGy-D*(LJl~wY&o)YEh*x$eOHo9nWfu8X)3cf?4?Oa)GnaR|P43r>|-+zlDl@ z0ju=pPb?USyXnT%&woaQDh!EA^6%iF-@Od+&z+x-hJ|Inw9Az&^WZKJn1M<}%-Fh`x1gk@J!lxW<4*SR@o`;0bmJ!mi}-Pz6>z1O@}g6g z^ex3!9l+-ljePy0`_eA_{|4=j3J(uYmwsFJ-(G+hp9mx;ECeWpIRIcVFfk*3|L%Y# zc5Q(|;S~g2L{3g_=I{#P?y;^oDkWveW|+^vd%bo4Qm68J?P(W2Nb5UMp>|NAoh~Q8 z0VUX~UvZka{NOj5DYkCO`5gn}aIP{aH^n)y)f@JOw-h%&IUhAYKUwg`H37`zSayv9 z_SB>*5h02$jy{$LjiI?%Erc~OkY=AVLHpKKbX*Yvf7Tz>uBjsME$>5>=EhIW7e+x z?j3TY+Z_t@l5~kiBfunpBH^*I-N0utoGvEB=P=&@D)j{#LkT58Ovws7vOeBl8vwi< zNal(C_3I4)u@}Bs^u3bXU<85@P}1*}#v=a6gmD}eLSjsoxq2texSfbjySGH9~k z8w&^-=j)@vBrY3JS9lCGhOn@(x`6-Ec`#c6hk_!es2D@5B5Y_#1>7i2@LJO2mfXn= zcY6hh1f1cZR+Sl!lD?GM9I5y=;K-2O{F7KOYjSG=oab<*@S7nI1!ggq++L zybd!c5`vaV^va&(E zaj=x&x7BP0*-YoF=xWsDFkXBEprcm(iOolK)xF+r0O2|i&*BesNQLe0R|@Hb4&5-m zs}LeC^nWsNS(6z-2_4K^JA?Zvg8S2X>Ns#>Y>Er^Uj_sPiyRKZzEr#Y3&!i9PGF${ zb_$lMzs(n6w$5&!3xCI}b^C>e0P!Q0%AYJo?Dji69QEm@TVU<{_WNJrz>E`+vMe@R zQW_qQc57>Ear|!F5fKqmNt_XY24Q7m9J0;={~#S1#H|%5u>f`s>|LUC$$%ZPehM@IAo_rPMkOSC zeyMnVHb6E2e!O7Wj`YGOfZb{Xg9!5IJsFwL*w|Mv-G2%TvobP%f^fH5>j=O)6#MiE z8qmKNYnaVs>I68qWv;i@`5*x~%n5)aWqKN{VP$32@N~BiLWPm@h@67L??nK2bahox z(IpQ00gD7&QmN2C?bm#YG)QrRNgTv-g_ijTht)nEno|Gl^7gEQ>V)#{hI$4N?57Q! z;Vyq-_nyo!{=O`UD96Lf={In2+HF2?f6W*1Dr$2aRV$476cu}WdRmUJb=ebD7v7`3ecKAqtK|j7Qutg-=MRB^iUtUGR=@m+oH%$D(wC=L zpww{EhOppr+_3-8} z`=5}(R#m+R6`diT`N!wK7$WWOHVzy-CXht;V8{Uzc_voQJ#zLsgz|umdEKQjfn<*% zvI+<+0k0$DOg*YN4Jql*i1%Vs2*Qy2`*kwP$~d6C5OO4|p+Qt{f0$8P8a^|l3|>?W zs0DABrVOeiUMIBFVSk`dxVUbUHWk#=q_nlQEiK)3t*xy=&gSKR2LE|qCL~}M{=sGh zg-TS^51R7d=>Aw&EU&0Oh+UurJ74s8ca{Fpni=p_hG?R2iloJwqI-u$h>Wslj!J18 zSZ9Z$h4`Ul9u7PRH+e89HMh&jojM}Z6U|>RuBN7@6|iNg1(E+0lV8NJaDq+UO(Cyl zG_R4-{>8f{=`lRae;z9g%G$q`x#p(lz4EiJqN3vVW1gbcgYWQmW_kHp!#M^{RQmqi zYl-3GYuIxYIXNq#K53XVgqJ&k4}TYz!vM94UfCI7$iu?}LQKl?adX-(uAi0A_`iuO zz*9>o<4n#|`?9#6Q z_{<<)M<0s->?UR9nb#h&-?iG3E#5c(k6!#DZYXlvZHTWwZWyO#vW>}Il=8v*?CSdP z+C|0c9RwT#!g~set)E%(v9V%5evkuPQl^cuAcv?8zXbv{8sgKxOypNkx9<*A`1VQX zbKnHuzZ2&3zu^v!&cu1zgrL`q=)P%UNb-}(PR~4_>~~i8letyt|Ngzo%fo=7{!4d3 z*~QQ`Psep4?@w|tPrrz16&0P%dMR%=89Z=Z-Iq75PkSj-E&J)JS#cNus~_gOCb(Yq z5U{U*Tzk{v8J~Q|l75XUJcwnlPrQCh*pKse+A9^QF_5t$`Y@N}X1t2L#;)l0Rmgbn z#qRj-WC1o{9ssz&K^-R`T!4)VF8hOCMf&V6CeWrP)AU#j8UyFU0%42hl%ON>;+p{o zhe5c)YP0YgMXLK9^^2{hT5Znz{BRD` zObqB}yqIb)l~t0V@spjMUBwwb6^)1-BjS7I6tD8a`)iJ9a4&K3Hvl88*ChT;1i4IL zD@|*-gaA+qf3X(n)$3NyZ(qtkAOoM|FhF5^;Uw*TNbiBWJX>K96&@}KOelf-+2Nmj zl=$qXTENN4%FZtHcy`wxN|FG$@%(t~0qjuF6SD?OUJ9xk00h7Qe*ilj$FKEhu|8hF zgZ~B3R$9HK64^rlu)LHT4hg=q`(fv zw`eHq#ZBmY&~UHb64+3P)uDpdT7hM)2yhe0{WH=~vnaDxL^4SKQADn%zdy6EF!*r3 z`eoeJ=8J&$lF-wKf>H=bv9yegOa&xrJ7djWegW|MP+-(GN@9Vh$Zfmh*}j?v6eeiQ zd{I^w-yTXXn?JnRn+zHl7$`|j-UAUwz+)c_{E)e7i(&9ea*ENQLks3#8gvr?g#$DJ z)ZwYM*O?LFOn^S@z0S>e&4HBl<^_$cnB*|XXAs_^p|t@AyQipn zsSmJHV9h!55-qu1tKVH6N`j$ty4|q?fR&14^m@VRM1Dm%3}6c2@Hw*r{-`sVuL!ut zi^lB=!3QJfo2j#-0j2{SIt8On$1i6-T;S>c07UYo!gmH?gWl{%Kg88Onv#w3etKPC zJ7neNqJyFzjLT93979mUU)~VB)Qcr38iLme*mNQRdO9x5Y;<;BVB31EhP2TvuJxkg z&1H$GJ5HUK1Y2bufiwj=pb@|{f3aDZSy)Ex_+~QG@{NOX68P%N%yD4cn+0$VRA^&X z?pZ*I4b0H0{C?`ltI0!@Wj0?0nidWYjKoibKKD%dJJ zP6A*_tX$vU0?M}w+!ahrOyGJ0*B9gyXxH}Y3Cm%q(PK|ePJ(VWu_qCqbCQjKUHi%u zJ(LkX)?iVA0GS4xww$!4^mM_8o64=QXTZ2Yx{YK@VuM#=VTpP#77F_HplwYBpOBM0 z&BLXj2t2v4T1pl7#c6oJZ{>F9S_R74HxSwlMLzjuD(LQRK^<;gawJ~ zTh~^<{aVn9IqP{JRtk7FAXhJbKB#rO^hiEvZq@)1gyjM_CDhJq9XS*w`qeBXd zLX=fkm%!(8#k&8tq+-7vq|&dTpiB@JzoVnA&Nd{#kR(2T&PYp3n`JSL{{8!8#T&&M z7-1>ycSbK+@RFj74$FfHY$lFRx7#31tOHdxednWpm#Lj zKcR{No&*tm!Q^K>J+c?a{(NgtcW>g)KnhCiVxO>5bY>$Lvu5 z!rI2h>3om_#N}p;syW=1ZPFo7WDonA&l%t)c#azYs-c1|l|{oT3=ou@1jrz!2f%bX z0iFs7CJ^EyK;bxF?se{$G>5jYuH+<|8(TlWA5=QRb;XpBvvTFX3#I^m@Q4{A)IU zh5wq!>$nE!ZYLnzl}oi=0a^Lt&Hd=ZNO8MT0fMd#tb`RO!SC2u4jxN*f^|%qmm_&N z?4~#%kARGWshAxA)gY12{yj5uMGcSufGnH zbJa#C=}jpT}`|G%LCo9875;H_r$s4KbsI>W5Hlb5#F4ZW@5RLu{3|9D6@tsM3V=PE1Dc2K|Tgd}y5B!Hgj)iXXJG$>h~sZuJy^lv|{ zoS!oVUlh))T&@QP{EhVllVT&*up;{Am`+>l=ljManN3v;lrCGS;mn_GxC%FuKYSC ze_hIEgOzIo_wkRk^go^$z>`nt6!sFjIhl_M&xIeZZ~C@ME#f7H_4rVJqwKSQXqNY1c4O2gXjRwaNqz3DEq#U z@(zv{FaS7B5hXGA8_mK z0kA;)MC|i}@>xf=XNRvE3F#F#J@!N@cd{`*4(_HB{!qe~$5-wU6Hxaxy+hhVxhmYe zMp(+|+rG8;K*fyi#%^xcWTz{1a7Aj@I&B?nC<86X=3^HZ{u{dx1EpvG;jqIM|VIKhc(_9a$mXPmL72vSJI931H_qVLw7fELKvg8rV6x|-V5(ln;_MJg>X z?f#W_uiRn$h~2xOAQq<+($v}35|akSxK^+OF@fIa+%Pt_wqRD%&M)5v8Ums=+TcVZ z4I*uBU*G9eLf?=-Flm#ZkUqU{ouUtG%rRWS%I{k>y|(eR5TeAxaetxH(M z05e%vWrZN`PtC=r=RcnHgmV>gF2qfgR=}=JEbL^mTIp_zeIIiiS9?PQ7kCyYtsb(B zgLLT}hr*1wq)6VTAQlNBZHp)BoTB@<`uS^csIaXX)7aTnBL*v3FJai_)fp1k5Hmj= z_fY$?y=7rb-I|nh+@y2&x9+sGx}WQl+D4LC({|_-TWE zOcF9O=GMu;yjd`JI3Xkz8``kGu9L+{9*Mu4ehBpTRpG5zw;`ZlQJ=FfG#lAba54se zl}m|-qB2LmZ}WU*niZo(zf7BH(g)eR89Q}33{sg+sgQ!DE?xex*l9K-XW!6nPFsJn zV-X5$uh*A9=WZCt54i4L3jKCoc6P&`GW$$!Q{3QPb3z3^RbL)D#mdY|9BobsymFn& z%&8?SoBM{FzX`l^h3vG(kEOYN>yYh&ij#93!>X3bg{@tQ{o6v*tblZBS7t)UgyH{A zxDp(^p0#vpG_0FiacM{(E*TDbr96OjppTGHyn0asv>%&A4eS9H4OUcbRYT(qlv8oV z!+y=9hATfYRzW1=J!O{%=K+?W_GolW|r2Gm9k&0VQ3 zhkTtcXY{%>>ea^W)c8?E54kXO$|lupjL&iNVC{w_Aey%fzso{(YfwHYo}g_rb9IJf9g;Dykbhr0VMeZm=cHYUUtrxDJ`!F2thn z0qWkgcu`hSk;#_Oe=t;nZS|~X1j!pU(fga|aEA`F?!;9a*Zx%fT-}*s^3)fMXw(8E z#RynX$dYy- zZVUz<+E^YM0%6Z7T+&IMT_yE7r{{kQdWt#Q&+)g;-B;nhD7Y^-FI-zu z%#d9vV6nIim|fx-%etTPckVRsoE~X;A0%g7a*PXd7419ihuXGRx3;<-Mq~ zi&NJXWwL#uJu30lY_-9vbMV3EZe~Vzg{wq(nFuRN9?lxPQWTkl8cjwfQVuLftSW_U)p^wx|l-u3e zGOY2#RZ5jT8uLrey;J%%<^uQ5=W@v)N8`s_*RQsLh84b=WZ7r?Z{-v0f@295du7=l zV^z_(&$V0O>gI%NawYMOiI-c=9muaM_XjgG&DR{|=s#jTM@OR{X@6U#cCWUjhjHUbC92__FqnEG7ZdX+S4+f#QF_s6rDWF)eY`H%sA5EXamZJ4-D?+@BMA?j^ zQ;&kE!*2JS?)}aA(6GukxlhS@Cf4$XB9}Pr4DoLKHm!;cKf*= zDsIT^MK(j(7vt@2G5p+5k{g*wCPc{RV)GHT_aiQspeB+Ren5^ zX49~wn3o*L%lgzb5T&SGQy*g`x9GJDqt`P(Mvgw{Ps09X zQMuV)mG0mot*LzO5e+-_YNI96I44$$#1arx_eD;&1q!1nuw2^{wJds6umBX^AHl8dYo!fr{-PQI*QA;a>F)t+fcLi$JA!Yn$9kHUHuXF zAr{^Vt9P=&4H2>^rW@IOG_%{Z2A}kJJqYaipyuqf<)=temg{^le>mAz`kyQB85SS1 z&^pQsz9DHcv#z|wx->~1KyMU18GfG_&$<2j$;Fa|X*I(3mx;U$rPE?CuZ*z{U zBW=my6C~7(;~E4X={j}IC2q$6d?@-gaq9=4AH9 z;sdk?F1PPk-`DaFpKolh@uo0RbY^GfRhX`FO{qA04;oG6zKAOfUIc&Ex~;sn7SrLt zN}dz*o$qaWkhet%TJ5+HyRqyTY_QXzoR=|RJ%|1(&KzG`E-%0?_3%3X)qX|T$?)lO zw~1SKIrB44u4K>`j9+qeRPb>am=zh}bM(GN(+mER=jTseNMMt$I@@X6=CPu&nPm{u5yDusJ|RMH`5W)oNh#+7<$?Z>l**<1z;wxWiT-Jh~eQzUP<-m zkW*8a6G#mVRICJtW`f2X&W7983F7ZmmBO0Q6LW0x3*#E2j@}QMt_!rAuQZWF;UV!u zfULz5;h;*ng(a%hT9 z?P7EMA~{!Kq9sRaSY32Bm)J~fv{yb=N4`D`x&2n{C<|3Fy}|S@B3R}XEq4laT{IPr zBYI&etSadme;0bf;o`zfvbpx&x?3y$`Ui?7flB{{G1AZtgYrLAQG@75TPqu|rI}xq z6oyFrW^@`w#`3%@(-ulBAOAmJ6w;|reFy} zOdeQcsxGf?@Vpdruu8jOt?O>jpz-KS$9Et0K#)Ca^$O98#y%g4kbbDT7C*Ca`bndj zTbjE<7EOfhu}~Fvq+P_xX@*sujks3HN7MU(;cn0Q_dmvoMEZIo9TDk&72kc5yaX+%`!q0F<$m|3Doii{o^_M?aUH% zB5XpZX9o{I$>Ev;wZ4{Il6>&wUt^=2@)5Or4w>ztptX*W);Io#M|)rlks&DSNUb}2 zr`3C#YfIywyrrAl``KDmW#T(3@A@9FudV0M3{(DXH_&{7Uv}%ohc`5N$0(B{X%ube zPxzlb{?KTb$%kUTt;MOq>S~`x{r$cq@x*)|88mV^PGuvLJge0be_HLa_lVeEL&-gU_Z{5E`WjjRK+RoI*FRUUCj#gIfCf|M;cRxdy@8b z$l5hHMD|541&t*2j`{n&am;_mMa2`H-&XNG=FOiQ%@4Em6%YAHH3=WM%ahWspsnq_ z)+@H`FW9u4SN^?jQ18G92&2pZ{skudg$|^26k@WovB=V zO^&M1?JMV4`Zm*_v}W_RAc(6r@U_{My-qm?ayj=HGiX9+7yM&zpaLKInm6K(OMjP?nS(|745(YAxDoZF%ZZ#gOss zMj4a~TOB$-~8f|*k1#)MH+D{4!P)Xs~-%csja+JYVKHShYI zLG=%<998gjTfUc9OvT+<3rh_}6?Hy2tlU>_I2;=4m z?OzgOEyS{iKRI+!^v~ujyf2{hvEsYcyklB>*OSFUm7F9t{@IA7J=R&rb6e>y`<8ml zrJfhIm*~l6QB|B|66^5epEBreS{|(tJLgzp=9^T_`S!L--QaaM@q5~ej18{^x(qw` zxQ}}a2Uva{nmc})*NeHsk>f`YoK;^tl#~I(%%F*>SYrt_PGO}#@X79V$>~8x|V0fzf9UYn;QF3wK9mN z@Qb7B^y=&`>=oM)ruZmxKJ%pIH?N`|{cd1J*XfR>cfy+nH}M81`mX+tzEQP{?LxwkYg>a~W|T_oiG@Q|M{Hw)-P~HVjduS`ml&ZF=Jp5+-RW`HoZoPd z+nC&%J{&69kh@2nfuwro84=abcY zz60^6E00gPx&J<6!+fV?pX>X-v!^%DowYW~$}P5Di3kjs_%U44sx<2GzQ4u{ZNvQs z?(Z(|u6o{NAY{s_|0$$6{buLd@po5-UQk>gvrm`WIrLCQv54uCqN#bC*Fu8x^%br0 z5z&Yzb+_9JGjmE@V%BXAJuE)|dFj!OX8+@b6v}x$6^!x@T`fgPk0I7Rp3XDF*P7-Y z?U8V0zo<}f@em8u_zx8&%0Di@$*V#RL4h? z`}*&GH889e7#@+Q$zy6U&@UT|xWA<9L!s3y=DoJJyXHqKy02|Xjm_;J-*lC|V4~l1 zlHt2gdEG|sR>to<-X4K#r>Fg9uG+f^uboN{uV?QGTz~KRv27Q}&%S9ZH;z=6dGsJg zc5X}BT|GS|m2!LLk7ePzdz()1ShoZ``E{@ND%U#YF^BrJ8-TaX6LIYWrHbJda*Zi6 zmws33=_SSNbPTB6fxh6m$I|cW9z*{Z*>fPE< zcXT2zX3HAmZas+z%3G9SFzux-rTd4VJJb^!177p{7hiQoGEzsOE>C zP;SaTAun&}Z?vti85S^{;JL+Xw2LiF zwytP69jeg25?n81U@y)*BTqL#X?*6K^nqF-{%Sv&M*%|_A0C}EJxt@bE1}gtAvk|X zPTTNv`YDV0TD{6)FRdNh16vG!zMehR7UUG6$}yY%>z8AIN?22Z1AkcNn5_D(J*=ZT zwE>+21w~G~EK_JST7_0sH?Q9OX}K-%O8=DQ)+2T&nQ5Q;e@L^VP;CkQe%T~1!`utw zG4VI9L{(GpiN^>Ovr2?=`uRIKy5E&=eqjsy*_6k_dRu>bbtSh&*+tL>T3Nn}>S=JX z{kzv>Vj-mO$jYAPTviTo)%j)jRP&z4O2vUnX?~x6i3kn7Hq2~idQ=O^gzY}%Db7jb z?&DS?$KRG*dGz&Dz^i8|1qHW{oV+PN`ElA~s{h;Jd!pwU>9$wYHHn`)U&_}uI$Cw| zZi_)Mt3AnMr|I)jF;ePGrUuguHnTUYJ9YSEPLy{XG!43@T|W8QdNP0Cr3JIFvsxaN zUtZ+jeX+Z1{NvA2b&ET1*Xq)NPzmAd5;v2pb5e)&E(oFBS3zLm%JhI?n;{T8Faas5^s zOC?sTt84!p3@g6$_Tb*|%CEf~5={n%w&il;?Ri1@C$&qD-S*jOy!B_wQ4iUi6Ze8I z_57H!y!2~NH`T_;-%LgAw?Qm#@zL>XF=FqF<5(z5-Blp)OT)E1)A(j_UuUBOpMcQq zs$=0p0;i1Gnq6DAeX4C*F5z$5<|W$|82fQ8UgxgWheqp?qoYTvO5?ahv|CQpwzl6q zrK)qG^Hy=P%d4Mnrz=xtXtt=2;+(WTB z)1{eupY>Q#r(5O4#m`xB0}1uEwPCC_9`)6GI#Z8YmKx^d8FJOL^wgDZ48LZ3lXYcC z+y`Wz3M-@QK9_N>{?l%r9xPp@J@<9wZyIrDZ`*S|KZsH)%{gp2iQo5x?xgJ@RmCq( zp#tWgPZ}+qs*w%9S7vUk6s_Occ$<@UT%)|M>Fd4Z zqH5LU58+IX)S1yWS$l3lW$#~8C2;w-P|*04%paXeDzobD{vqwAJ)upks;bUeLqC@V zcq6@~vmdKQNC(nJz5K3vjrV)u2}|*n*qy@y6Ow9Cozhw3(!%z6hY#5rcUWE4SlaH< zo%=}SgTI#g;XHjlzQmKhpR0akvTpxvGx@>le9o;k*>Q~%;R-F6pC(WhzwQ&Tw_sqd z4jdbNO&!gbep_D3k@e#fE3X`ZL}A0Hg=G~!LczV12lES_jZcl`3OLXgcjw)iU0XQF zaNk`|*QnLs&Z`=1L?RS)XYhr4o0dwyQi85yq zhi&x}x@EnR9`U6Ehdvo3SgP#h)pp!?vTAxy!KCV7_9WG_5VlJ~b z@G#z9w!2U&x4!IydgtZv$?Jk;Z1OWZ&C{oPe=3Xi+RZHI$shTf$Jyjoq7!J|6`1W9 z?NGL^(4;(Pdl%3C!~6kf{d7$$D+`^sdDSE-ZQC||Bhd7W_qcS~%iAh@=l-ykU1HR{ z>T16Q4a#qsy-PQ>GKUiH-c_E9V-)MlqSIj%3;k=n@aWnUP13i?^rSaE^ZmV<~WdmWff)fAP=V>bY zaIhlnM#evWgDH)t`}EA#hw-{ohqshZG_mh6-rCo=z4>CmgP&EqCTuG1iyo5BrkPdv zXa6Usvo07KxrA|s9mgcszj&>PF|os8T9EWpODsWqbT!*b+v{g`x9d@esL0^QJ#X(5 zu1;CwmKK}iXDQxncYAg4om{W9c+QpHEGNBusqyyBuUDwwmR%c;jC8!@_E*HK>BoBt zmox$ALaQiqCVQ@I-c{x;)mz(c&KOcp-*$94@pm6}_1|QAPvcwP=2}-$*{ky#Z>oL| z^$5{?T3nrF_ThoeJ)vao4GVAPu8sZJcx6oU@tQSvirtU3QA?&DA08U2I2Epq_IzA^ zv~T%VQ@xk+$EcA#CseKHj97K_pmQ#WRJOX{nC zQ*JiVz-a0qC?6ti57wv21RdpiLT{r$XyIom) zk=i^`mf$?_euS|((YmmnIr*`!)40&wvNhLOdEN65Y3axE9HUeju4pS4C$UnA8h^eZ zb`I+5f?~VF9|A2*W;5rS_H&KzE#7)XtN6wDu-5@Yt)Z%Rfp_Wpmo3{f{t2s=w6Nf& z@fnbwyQ!evnwXS2=%O2o;Ow2oCbuEHJ8K`VQ!ncSQXb_ix`z2HtW;kohFB3zk$sLF5s zsHnrej`q27{SU(V+%Lq-YsJ-SWs{#fyge%sE+TdJCrfR8(dagIr_tSRf#>`JBb)fn z*NX0bp=ql5zN>XCEtYe6X_9?>^kfL#hrbd2LxT~4)PcG?dwOcd>W4bb#vS@c>Y~fP z^#EMbYjT=dD%EM54CPuM6V(mBRVO&o-uCE*OjmK?i)d4!nzG4T53{~6yq(-6>@+T~ zba3bTj30|Foo;T;?{}PgF!2J8*Lok?-nCgM(G8V+)HAPe*HT^LFJ;}Z`B{^-2!)ha z7?)0lLzmHDlzwZ2nBa5)Ggo@dcJcOGhf>ZREGqun#OG`|Eib% zzlZRCpU9MS>Xx*0G*PNnEwOboA1`F>s@NN5+qFI5#o^tY^ zfPE*|eSdGfb)+?|m~FjhEGHS_tqm8pgDQ%Q)vKr)_mz4>KB~+0{J-CNfK5Uo3W8L~ zD~=pHW(*y6gqQ=>9sCI$Bjdw1i_}&>y6fLrPrDcB94r_gGUZL~I7)Yw;i~(r*qK6y z-}|&wjhAM}xHU33=dUS`oU6TLr3asQjFyM5ojS`2l#tgXypG?!=@ zC2lXig9Aa9bx$3pqA*a`o0>mvfG6@}aF8Dod8t4a|N5bUNT=>T*ik^E7T#f9d}=;5 z1Ya-}=&`&pyW@(M*4~X2+YmM-^q?8W0QMBbk}oDFC-u6gr>8H<$i!ft=-FjA7RpM-#JzN2ULe(DIEe|*s&ni z&wlE27umiZ3SyJ=J$tRn_fDQ)-iT*mpKqR?X8O?s8+>=IA7&ape2>BR9)sASyMMab zn}=3cCxz!8-)+!x>Y3A?m}C7?^ISP^jlbYU@xt@fAg1wkfwzCr;^Ai6`sAk(t$w!d!w@XjCV=^;C{h5XP z$H(iE(~4v<`1d{AIy!^7vDm|d#kqGqR?r!9bFQOmZ`njdo~i4&cxPk?Vm4!R2Ls%O z_%LAi1qKzRmSuY;`>pJDm7)#ahnAN0#8FahB0?JYk0-B2ky|n z-fGE`ag8t4lH>Ch78l7(;_O7vME{-n`T0p`hJ!;wN{MtAXu!;`VFoFGrn4e*>9{+@mi9tdRU)S{;-GA~bTou{WK<<_m|(^|8Ss>ds} zSzUehzo$^+v3ojX<`|pr0em30PQf03DKDkOCy#7+d3j+ZMB}s3@ACo1ZoK{o`W>5# zM`NKT9$u4>kf8Lu!|AJ(^SIU|e|Te0EN2tUhH6dl6$1LDn=YiUI6cZfF)687@OuIh zSGwK1iQN(z6UBn&F;#EJU$07tb|N&OX8?upLa znG=ya8UOq9e2wMD;UUcn3C*^Pf6QF}{JN`=^7>L352Bwhropi;u+3j$Qn#T&0YkJH z&fvN4j@JRj{_Bj4ClIF-r?Zg9k42p)*@o()hhTPsk<S4 z8M5>1xAm~#!njJ)*RP*~_MgWZX2r%K-U!h0el^ehu?-WoQxJVCs;FGBwLQL@SEnFV z8SW%U;17eb)zOY@+WfA7E~^BnvY~&&Fv4Ne5h*zpXJ-)|9i8`{7z6yz56y$inphFP zdWug&3BN8UKVJYtvl#I3#NoK9`Ngz$ENvNIVsV6klFq z;Sh#E#20_XxnZ)|4MVa8@M|NiY>Jv+et!NBHu$J1CP`yxnabPq)Z%vVDe&2*M-9#aAs#T{5(ns5@Gj|>eZ8-&D&=-ac5n9^ZmXQzmi z;}AXI$ws$hhbO%4FvM!|vntf0Gbb1x8kla(g7{?%5pVI4+2-7#6yk z#oJK0t52(u{$G4t)#Ms^4eKH0{j3(%e1Qx;U!g(ZgA+d1R^e+kl2k=59v^<9(^iT8`qFulV=J zo%PH9tH>Gu`+2_+69oVF&q=ob{W5uPz6dU|-r#ci5ADQZVgI*zXE#jG(s14H+uFxD}dP6@9qN9x6W$9js@Y`{M6I{ z_zfPUEIszOc}_tslHLW zAvc2$ZSH^P9Yyw%4@F*Eo0(~-osAbLCX+XOdsd~}9fq3@W5LcQ|9v;uRTlq0Ex;+H zG~Da^{cL!^C)w6y5C=%Ug5QO+tLu9>m>|9*nf}1E!)h%H{2=||g|q|D?fGTlzmsXn z$%Ys)#z5Iq9__{A?)BR@-F2B6R8&&BscdFvXJ>t#t^3i=nTeZcFjjQ0&0;mM8lwOX zn3?iIUg{C|faac!(rvP23x;#o)C0$Gy$U)y?&r4{{r%k%qUC-G0~>J2l1DPe5Dez^ z=2#uhL>RY?IU+HWq&oexntVI2E`mjI{36!4j{AZ!QjU$tUJ}CF+uPS10^Zh|4E$}? z9qP=rD{d1ofP3U#3Aa6WFvVsl$h0Qie$4j(g;(FxDhb>EP0?=Cl_w(UFh0=~e`zgw z_aQ9GRe?7~+dIWEii8-BiqXr*XA6)SoU@2e%>_jxz(``L5ETXYkpt_1YhS^F>&~5Z ztCK#bU#f5cdgK=g=_NisD@Kr2jv5Py#&LM7G=4w?uu`CmH4#Kbg@iDNTM%XriJ zD9pqSy>Q^+dr32Z=qG1qO<-ul87j-f z%nS$9*YWXWHoZAnop&AVEZTBx53WPtdx;3Mu9 zC>j~W6fPOWGXfKx?_jGW$V6>e{-~t2H4HN{81k0`u7FwHnYc#e)(T7=VK5aVT6i$D zWQ?55XA#&ICmjeMp^(fQt=Na>l$3Vh$_zjI?gCuev3G9`tcS?&B_w>n_yZn;Z(txT zxf+G!7Lr49a&u$UlF3*bK+s+U16c4W>F5N=#>XOf5@SwW9UU`swPkh}JL5sD1>@?c zeRy?v1loD_`wt%67_U@`F-TD?$?@@V;t7BqX@HjnuZxtFlzaE@V_NJyph0M8C}P!m zgdmIr;laislwhFsA6R)6yRX2d)JnZ4ko9yOym%B6Rgj`yz4ISbi4i*te&X+9jS^%-@-?QL@Uj38x&7lX>JO8M z^8f`X06E|b2k*g~Q1dQcYDi>cEpl+WMhXF`l%5~qVFA2(n3MAXJ}FLt6Kj%Gjn@U4U~m)&P@(I- zaM(PP$-~3LDt}DKeR)dS+}xbl_1hhaG^yQ3bA0BU4lOTS~%%YLAEw8wTtxK&rsL61PoI zAp#|=3uR}rn;#Ohf;LzHVz~Ao9Hj8t;AcWWJ+{A*v2owvpwzW%jCfYkDQb2@kxrz{ z!1|y3`!^nL1Tg0ULMNM?RCn0UZ(7U~yI_v@Ix+DftORgCTFyvnJ{I^}jZCT(wXJ7h zVWO5C3a7z>!a_3Qm!2McC0xk1RolrH1vnN3{w`T>Krom7em2m@W5MofiaEcfO(7^aI5*du>)Iw^vPv*o{`P9RC(JlAG>&<| zyCYupk|I6kBL-X4bwBsnOadq=U%OTbXBIOnE3(4K+lSX0_U-WSZ~;smzP7g7tuDKe z^$TM#?1ZL`W6KLOSY5eq-&wZ3_r~Pk{cVh;i28}i$v3i#@DvTlJ9Ga`^swSb$94EH zZnG`JY$uj1MjO*_{**;*gZt`7JwD8=mEyyQJ4J1+KVpXLLT-M(GU6M`eXK=dOo4Pz zwD|id=8XVdiLY>qCXUbTz$ZR7;zr=kAN>KihMMRT_VF+I-5fD@#36p#%mn!F*iMZitDy8lfOlG!E+QhfU3`7)dQTQoFGSxfKaVh z1hNhxlHzHsF4TK8f#5;pKElJ}SXphvKLyhmk|)WWY5!+GjQJyrqTZ3Ybjc9=0Wb-L zaT&@xtgV;$Oyb6Zt8`yoFh!Ulu5^H)Zhso3$vQ>MfWzfsfB)WIJql{33t0WQkI-#3 zpolPn|1nn5Pl1!3z!q4|9JlE`L%1shxHs^qgR|J5UyU1ug@sw%=k@WNexZV&C|)ai zHMg$2yBlC?pCbJN+)`di2BI!S)r|rr7W2W|4@xy8Ds#ZP2*C=Mh9BZhFx(W6Etmhr z9RK4%>=*1g65QdD4XEjbp?bg!9)EAd6*$;bA>xXE55TF{z8x<}vhu4r5;W_xpJoCL#<&M(QQmEN6xxFwL zZoLPlfPfgNV6pV2P|{*7{6dP_2kc)n7TDqpfcpY=z??AN=m9aY7vvSg%^0Z_Pbu_V zHA*iGljEZJz%U>N0OaDsFj7zKiFWg7y^M*u3lALlLtX@%!Rj`-9&62MLWjH`)TLOe zaPtWS6G1j7Tu6K0k0@NbCWEvHOmrr>(aj-rxPLzY^I4W$yWT2P_HinNxko~u=u1Ext=l%T# z_#?#qut-`wzqa)YPWvf0)JrUJgSjBH`jR!A zLV1q!)PY#en~3e{z*K4}8j^@?xG22Z9NU3kP4U$ZhBmvXHY2SvC&)*eRE8V|B1Zb} z9DnMJ>xZKPnF$7z!=)gr+mC#s#y)~C13U`10mF=T<%b~vTwEZG6}%Mzc1QY`FTW6c zsGaYqsH+<&6<1PL=7p3;Dtxe2&b@cHdFbjF{?#REsbEGmjZ3Lw6-a#7-yScQ1t!H+U92Ck*7157{w1YSV? z7sTj(z+S01eSCMssatAIe)u+$XUQluf)$K*34B3hw;_KR6!h^&{waeD`emNCO{mTjhEWct}1ik$SF?n`5!r_*t%GB*$%mUo0{JL8md-&NMNK!ixY~Ql_X+UwWsggZv;009}|?iYIzKp*~v>{vDc5#bX>OEhQc2&zYbz>*2rD_Z(SG45Aq zt^jyJHeO!&5Fa20;Q0B)#aN}p)Wln4c^p2BM?s4~i-QZ0w|4{j_J1q}_~&jx*<{7Cvj?je>!fTW~8Mob6^ z0HHT9JPe>m1N)pq2+oReQt3cLW^#^BP8=|!10<}AI#msOW222{!B9D#S=9y}R?^Ur zh1DExiw6dN#N+D>y(B%A_YV;f+7nhF2H@;L@*KLv2TqBQyv*-5ZxiJ*$Ov;qEtVkR zQe+Ysb|4&A4g{W-Lk*1%<_ojGuBXRvkNaCye(%+mkyA zRo4mL=0prv_KM!T2S%13bv`1WC)>roLwJfXwAb1t;cyCn1X7af_~i7oxiD>l8{jQW z(ebtr(&#p=SEQc;IM2-m3$>r|w#c%y)Kmfv0kIcD~qiL-0j1jc|5KnZJFR zi&`9F3b7;K#v;B4-#ary?Ee8Y@6+t_WupXlapdy(6g8MVf?83}T#|)N2G$)iA#tMs z>5K{>&%_nm7wrwCFOHKZ!x32dVWNZz+%X^Mq0v0^K`duz$M^3SQ48SfjFBZ^8MQk_ zt@_kl=Xsn(fn-U*`WVZ68e9%hZeNZPe~xB~O2~6g-=@^qb1@&SvT+TtuI4e!ItFM^ z@Tch#2!B3!&wNYOKFX-8KIpJ8ZA_pxaWsU*?Bvu`Zju#3A(ojBRz$$xk=Dn-!M0rz z4o~~+m%-`bK2W%%Bh!I^dEo1NGjS>NPb=|uLSYUQo#T$9SH&EDe*(vczD79xIp?@V zk&e!9bdGj*kE@!^GX;f(v%`HpY#VYu@f>zQww~l`PzJzl>Y;4>OFe&A!c$jRIIlU!ZZ=9<^9=Q_}%&1(2qj z@1P|b8K&$096pzGuTxWZZMuuyykplcG@s&e9>a_B1;mFsWbXyIi>2~65yvnzU(dtX zC0^SPj8|iOyDZ9Xgfj%Zi&JY-agB%njGO$41y6&T^Mc}&(sL?YyTGOx!IK|f>J7ISwI=v`XmcPd-<&9%<2R|<0~D(LryefRIG&=?$NC5V*Zt z50-nEDiH&M55}y57d#KD~c3V)(K`&nXK49m44o2*SgVdV1G?anx zWb_y>oYO%K@vFOV=~(SPjg+UT5sFr3HF1YHjm4BfI25^p9I(tcu5|Pe2o3w4;0fh$K+2T zFE7udTl5Hz<=wl^sg)E}FhXPz!LiL$=9%np#Lbxxq; zAW|8a^bjm?trKcUpz(QBo_9VQl;BljFd5q%rju02c}75-JaQiZD-fi>f#ctxMr^&! zQUyet^PS;6rBxIPWTj)SoP*PJX z$M4|^#8>AB2;k;_PDxFDn2U=lR8|tEx37YdK*Ax4IuFN(fgmMkT=4un$=U?oPH9gK zI`Nfo|KuDy2M^VK2>ZZiE(k{P{AmQ0!9;cvXVConAN0fyP;NjUrPtbHDco;hprA^C zgTn_*IgUcxg^fVmb3d5WhSXW&0^^htpTV)5{26Wm2z5I%^HIjVFli)KhA3mBUcO`t zo6Q`P9;*9D+@_AE6?le+GoxSmwWVdhZ>-;0bHGThP{Mr>|32WU#XrLbf8w+i8NkEC z8xs*{fIesDir4n}l$GGThsz+QaHx^qx3|}@y>PK0R9m&yTWact%6=wMmN-pOQU<9# zTaW7gkxm*1AD@DTst!7VXlElN5eF=sy`V~w)qIB)uAw*)h@ISl$MOIxVG$7BK7reU zcUaEb`5S^v@btTcGj;&=N%aKxD?op8r~>f7ufMK<)~MkPkzN2r@Ls;u)Lg(G$DW&9 zo~Z}eyn@EVGr&@mV*TE`b+9TQzj?z6Ja7$1eK>X6Zh_6*N8T7KoHsGFFci%pA;ALJ z;r|(p?~NNa zpD~RVt*7AD%z6~2X;gEdU>*pRHIOz$PCmy z_vnzgAs-ewOsaNtmI0G)e)ID5)S3p2Ae0qK`)Mo^ou8L=MOn$A8^qHXAprpHnULj+ zuY-u#VUYQaBuN0V;5U?U#00z??`fo%ppwA$m38IxC2)BNX0$l-0t6@cl;|fu=*Xs5 zu#k>X1u9PLei&K14?ijkCG`bF6y!(%fE@4yBIcPdP`1o~#36=W1W}SUxxLsv$QTIB z2laX6^pM;yxa;|#X#^&pK(wX+0GXgVp3gASO}+&-#RyTG+yb&1nn=WkSZi@yR#aDX zHL}&06$lbI44W8Lg8JXk87H}lZWkBi-VGqS(A!{yG-5OQl(i;hJw4G_xoFxQj?{dP zw}spbII#npAryiKEQucoVQ5a+_LXiXx*!NW?5pdZJbF|!LEDEDG*X#QI=)Tg_SI$i z{@?bouy}vfRjnb@*2T3@sdF8Imd#mnEB?Q21d0oF+BIv7LHfdE7viHUCMJW_&Dk8u zH(LIh{BF~E!5n%!d90|-y+Ez~D9qc)=7GmBA-uAgd2HimJKsiiUhGNbh#tx8GpPb7 z?eth%af7Djy5NhE-{Qm-6MOl3rUuFSU=_iDvGLUu+E;geZbs;8}0 zrCN`!sg;kVG1dzwKNc3KUuF{Re$?HS^vGH;z}mQ=bM$JFqPwtif=6aot0AgJER*4^ zkGcZ)(^@Ko&6Dj)Qo!LrlM?~Nic*`GnU0@dofOH)o_LeL?DKlM{u;OxUR5G-9%Q}bHHn)aMz-2dy)Ob z8o%(&;4rhkPN1DJT+gYjj^^y1Sou|s!Nl-=C)Z>dq1JNe{Li=2d?^mc z2^Yj0R+hFKR2hzJYIN+$TPmhTOAXlr&0Cv=0+2O0yJkt9`5J&6(NFONv{|18UVs5& z!CqRA;V0I~50~;Q+I>ip2_;_rYNo=ku)|Hk|~f{0Wl3c)`H~ z8*~elT^<*tz!{U{riv2{4^wVHq44tEJGwjQ3ZmS7n*3t{he9rQL`L`QI7>%bI^n|B zjtd27+rTtg_f*~Hv%TnjfE!}C1HVRanI2B9vIHW0Sr+=zI@!GeH90Z3M;rk~eGQI+ zfv{EPT4Qz={GS#e6u|rzq(fP?FTu?n0J!bm5o0IGSRK!ZuBQX;yAIaL>vlatH(Y+izPnx5W(K1l;$>baOR z@k%n*xheQ}=9vck&lM6=)x3ZzVP1;T+QVZlx!bS*tsy$YXsgW|bHo-E;h;oMP$eB5 z%!>4+<6?bIyRmCX!4r%O_I8b;wbfe) z=_pW8XdIyhO@Z%vl@ZGcXe5bc%yjd0L2v*NXP|NVAM}9M3K5)vV79fh+Zbf@>#Hbe2BIh{MdgNX{I|`L z!$yhUCwypG-^c3et&ws*Wqm=ve_DJ1H4qbXRyLuCdjDj)o&yHmVYN0Sc4bs-io>4g?PfDpTAM zAY)n#aEx`6)_Uo$rJ0#NiZ;-yDBrM{uolqy`{xX|X*Z?qbQVtH8f=)+5 zWx=F?xLaq_=z&s}@p%tz6)cAtK`OUY#?F7v$+$|0C@niqw(IM?mh zW-*8u*^A~4Y2l+eORza%79d9e>DP~{Zy7o=9&0+@W5<4yR-}c{43HrfJoZk(Z2OIM zquqt!fbFm@E(a7NXAYtc1TJ0*ibM$DjsM3;$3#Jnh|&(UqtahsCF(Q-tJ z0Nq7Dy7Mp5gGEWg1PBFM6uarbv13=viRVAG&S&EqC&AJV;HHg?Ua3sr`=UHnUC=E7 zu^R^o9awk3{|ba1f7}xO5f73dY%KX6AZb+RhlGR}K#mfVXxK?s{>SB6E>g@ERj(qr zG^}#)+c0rmcLxk5aWzKEhV+`jSrfj49D5NF@klNC=U8@+3C^a3l=--Iw>U^5C_iyZ z00rtVoMwj_ouEf(TtlLwctmy3>?gfZ^s8`U0?`TLT1XSedCC9;`{8RHV~(%oqw5eX z@j#dVrg@M967bnT3A#9>u?kM)XTkH~V@N3q8A&6$m_!os5uY za{59`MOuQ8sSp96jJ$jWdL)o65fuZERt~W@MduAMYZAwg5$Y8$3^#rNUflqSgfPG( zM@KZyV{H{i|3Ro&AOIzQfb+o6Sg?f?BF$crGq@)7TTIdUN7trkzJDt$VV|mO;)KTpTq(K>D8#E! z9Y4oILgXRX2dDW}eouoEf`elVA~dR=BRDJtXo=hcDsj~HL?8>|#1xGaXcX?C<*SVE zK{Ir?r?~hBC4fn*t_NJeY0%*zoD!7nXx7ek+R@@PPw*;scsvkiRufSMH07jU0s%Cd z{;@6QX&MU8U}KKk>IFu%Kt~?pl$&ty?RFlZ#)bnOE=ezmRY7|2L`q5e>fnfQ*)XoZ zt6MrfJKl8(nr1L0u*IE0Z4ldd{c4{55&Qx4oOiM7$Qf_=8#q&f0R;#Vc4`E{!5rsK z;!wo%E-rA7ODVI;{(y5ZAmPQMMv+mZ55W~7PZ2VpN-0O>Sc-luXa~}EC94^yY2jEi zoRJv=PII~p-HE~C0Q8m(KeT}zd(-l}rz;?x)A#CIH68{ASxZ_Ps?v%IA3VqKANztd z58<>jq!co*K=@}6R#?sGY7%F2+%`(wSa^7QpWFXW*MiV!);_!Cd0PrvmKv-Y2o(&0 zEpCo;^IBRFPjn$fC6qpZELp3wqt}o< zVTNoBr)bC^vERKR$3wHbV7}iE9W)zIjKDI?VL~`5dj{<^nWLXcbFcT~-KIIT-q=Bu z!0w-@AAra2pNsi-P5>1sMyk+2BprNgFJ$85AlFe&dqL3~8@mAq0|Qq9@Z(%Idekkb z!@;RZ(MyuLrSb+oog5LYNbmAHF@Y>t>z*Pq8G(b)@Tft_Aaao@5ReHnDk}7lOZDL` z^*!W>ViOX2YS#Q3xw}qxZBZRr<$I6H<>3Xh%r8hRkzmx)k z?>eF%BBdt4IF2A z2uP@iibTwW!3nUHrEJ!AgntK)AKWS29>{*ONc`-0hZ;%$*5-87RZt)ym2VbKi%$2mcR?>&e}Xr z^YropPs+~C{Rme>Mk|1@bLYBm4R>Vo_IRwFLOd`A%L_hi3sy9;dj(Dbz>5~2`n2^{imP^PL6@j3()SOl$It*F{2;qLBW&$nvICoqk|COFNDT`X=OMPuz{G?+s&g>Az;2t)>ftyc#GVWd%lzZNajr7D zL?a_3H-8mcx`L!aHy2n5Hw88kZ9?!~c*2Jcs?*&|uJaR_K^!G&!0p@dy_+Z~n!bPM zWc2W4BQE|Vo}a~km~VtLNdtq}C(?lXnVFf8rWCC%-l#G8ka1(<#rF>P3q(f-wL*b)4AGm!P)2xo zxc!5++$!4QdtE7*tHN79GHQy@Ncu+DuQrI6P|?_^YJz$p>H}wxuFfleTMBpdW_38r{{GS^mcK67+|8{vGHP!mj7_|!K&TL!u zDZOKq8?e+5ple1{;b?1y*(z&mUjgs}M~?ju%nOxbu)PAkgQ#z8$`dJG=Dz(ucOoDC$s2f$Nr$7#q&Qpule4X~Z_!{d(v% z-oH$N^&d4_(d-CcwOK+X`xGX#786(2eM`t5Xm`0rA-&xaZ9= zBFTpuU)T$!6<$F|-#+L`ad+`PqsTj`@GrzDT(q4VW7I+y6!~-eS-Mv?uTjdN0A=Ji zqJ)S=_^%DlfhD4Ka&$8CgiJYfw1M=yCj>n&D82%yM5wP+$Zz87#%WN57RBC6yVO~L z<7&YVwx;q=z&D+1|Mbk7C?MB!tx`# zV@%0e%hEE%PqFixjdG&Orp=oH_IM)GFkYeVovl^9AI(<)#^~tij15|vntmt+{SM=}N^w zBdYL`U|Zzcav-S6`g*6f1v{o+XqM1Q%-_MYpFs=Y(zN|-in0(YPSjWz!?psb_1^cX z_w)57x=si!2<+inLkol)ivs}L09g_~F0E~%^*p^KBoXysmp-DAT?GJ!b1*`R=FkjI zO_k%%s*gPBQ(WwkzrYnLOP~gh{VGLo{R_qe>Yy57^N-28P0n_}Nq!eCEJhuyBc}iS zd14i}b5q|7!$ivmKha)13n~v??al6@=f8gc{-8wfx|7cJrKKB{)d(;-IU*$P|NAyk zi$KQcs%)3!_DmbC{lPi!f{B%*W+Mu?gJ3KqiM3@r5OjF7lan?`-Pd3~focDdZ2?lUOI>_DaxP8ftNjn8?iF`RyG zilzXx&;UJVD8pho$pIjIsE5#MgIwWO4$=r{Y|^_XY8spoh;Gp@fNQi#2m^}fg`OW& zGB=MujSQeB2Q;EnLEMHe_pdcm{N3b-D?LI-SU1(1A0!KEP|A}7x!vThw^l(VcKn}o|tWGUK z=Tim=2=gGVEk}@R(YzrF529(qS$pWIAa;=RDbNoC=5Ee+vc|j%X)YM?D?;O@q!f~I zU?1f2sFYoBO3JUU{A|CXtk7g-22eD3*(4%k+>A^JAo}IW)~j;u0?$IU*W@q{h_9ki z5x#>ui)4O~?sxCrC6yk!eMc@dxJZ#>)DXb{y@0fFE*(+-;gY`N^HBCYVm%#2BAB{* z1=1`kDq614s(2Rl058OL2yy2@`VlP+77gG7Irtnc8`OVsIXUxOreZk24d?XHF)_Ke zd@s7$O3D(F3b11zNyYgoGjHF17IH!ijQoRyL(cYj`}S?}@83`-Kn#xqN4T%Py90Hk z4T>H_eo4ssAcBIR;o423va&K#fFh#fOznjvG0_o-lyYb4P7Hsg?c>r0oclLFSw{QM)~$xvQ~$O{D_sDfpbN}A$?Awh-k|%0 z23{5j7HFN6jjdxRO__1>6A_5nIyr^0@(}8`c;h|1=v*s^{fpjn1{r*TtSdF|Z{o4K zj%c8u_|SZ`-OSY4`1t5hsi4sWts#oSujVK47O@C+bC5G&o<3#35Q}~OWdKoV1n@V3 zCGli{Jo`sRKs$w5eKNll_q5U|HYrJ#Du&RAi;I{MJk-T!l&OKu2U#Yh?%wbqFDu)K z9A{(m?hoq-2-*REk|TM9VC(&1^mS~7&ZQi&?E z(@LE5Kod|ZL4JHtTwII4bIkE1lmKL4nvnc9B48+kN=qRZcoiOkweYHXBPbWNED7Za zK=xKG`A?xz;tv$J*vL7fub}ZDGCznyG*Z;6@B#;tm@5E&AU4N=ix=hMYfa)}W6$M{ zeR27qfHXnjwLVkBzpRf9%V>J~=J4xRS@*A^#6)pHWH_CjfGZ)T7U=zMmkfqR`65l+ z2kVaCT39Axku<0WhNbvTFRFsqf)D^KB#v!*fcgod97H=5hA6Sotvk*YN`=gh;nl;1 z1#S!PU!BIgX`4FKS#;;%Ru~8!7#k80oXYxl(kvYkL z{O#=O3eG^@(D0ynrp9l;d?jSfS9GPMZ~E>P_Lz(nI6V&!54?3msitFB1@)qbu{pz{iqPiu!DN2L=vy9Z*wMJ?tG3 ziWzMN2Gou(3ko`oBgoM;klRCa#KkyVx2l@lf^@oJ!v+vXt)tcN-}7Vj0nA`=nK_kJ z0*fjpw~*qVJmGR7kga$>h>lHTDv;0qELs|WTo;iU8rD2~U)RxtaK+cJvvG581CxoQ z3{?^@Z`xW#_pL1#983b2>LVHN(;VDD#VM&`@!*8PCx(2*^zt3Gufwzr`#C;eP!=@r zFF(Y5>)RepgOVL5W}oUk{JvFalgg&g=NL_%t$*Exet5B+$F?iAR*nPXw^tR%JD0k% zBka28BC@s2TT^Qx_r$9ESXOran+t?eU~`bWKnB^&jcY?V^Q4ds;_0;$L^6iwj|4mQ z=g)FEfLf=g&94y(YjUWHIlfsD*kKN;h)$ZG8LzOr^6 zYVf1SoEDu9%Ix4RnvX5`(cIjuY%75oZ+d!n;U_FoeIP|w;v}1rJ6@$s($Wu|Z#+T1 zX0!JTg>Q^UIRDQN%>z7$|NZpe`9J@HlXKbR$tgUbz;z(r@iUgKxB7-N{Q0hbzlEND z%Z0Oj+dnPr3zhcA!!vF!`tPS~t=hr8*;{%Y4g|e8*kO>)=|8u{j?!Oh;Gpp1*9w_d z!+%}l58yLcWWJ)Ji~O2lrYs-NwQ9>y)M6f5T%@%ND;OoR-Tb6Jq>G3z<;^qE$wks* z-0iY>*&9)DG#HFqA1h}luIxKf7Ifx`{Q>@G8rCYV&Yn} z!rVvUEn)Q1i*sx0GO(s^&5p)EluBD5K77{X%pn<^IUHK%Lu&_n8xkrgDSJU)Kn}W{ zg=LkM@sKFGrMY&U`A&gYKH?cV%Z&~fLJr}ntV1hi?fhV)9v^x8HwVh8@p~K|7OHfc za@`>rti*YJf`WfM-qT_l3Me1L#z$|<6mg+YP8V767UbH74b@ZT9Kgm*ysLcJ(75Z+t8U zCl<4Z>OrZZhHr#eyhm%OIG*;_Gqy?~Axc`>ux5r$cQK1u&HCro)dgrvAS)&PX)*@_ z>_IZflP6>ZhFqgf-v%&*P|YjlJ6aN~3RMc`HPHBGMaU%L1E7CWNRt_L5ceohe}gRg zdCTtRO|S&0^DzcBd)nzj;USr;mO`o8#XMn!R*_;rP+%yko-hXa2yz!MPjAJYp@>I$ ziH(Fglz<_XWC5VQC?11rrbr;AQ46zeXDi;XF6{HNR>NPS+$R z6<8z(WOhKAm-2o!>Bd^pfp36c(++3pAm}{|4Lvw&qJg%uO4W)2I1&%i60iBYlxh3f zO*h~13JZ73*8pgw1epj4i0put0YCyOZ`xy~Cx)lJ#5J3HcKuY3Yg9RMkXFf~Skhy> zbxO^R9mh3hYScoIqb)XzjgXF0Ki8$|7R$N1E^e&;S@v~k<@XPFjE3jU@(q8rp8$oQ zgKBEy&k0-)E;(=69ZU`+Dw>rg`MTYQWXO~okC?W0Bx)x}FJ%1~juEVdLEEC0`m!&L zE2Gn8zq(htk5F!a3k8J!!*^$NoAXaFQG>9j<@P(#=9e_O;`OxxR9t0kZHj#t+Fgi1 zkVcDutFa!R@wmjQ(#@WxTg)O8;{HLxH}(sLEYM(Usj4pfWxQ|$)ZG6?*qev-oVWkq z3}atnvP1|)N!hY52_X@sMQO2Al+dEcQph%TX%PvLRMaRTMb@a$NNGYUm8L>O$Wr&? zWUlXh|93l%-|_oigM2>k_iH)N=XT1nN~nKWB~luf5f*hRxz1(ug=J`^bH^aiSRM}e zPrXEW*baL!+}#oYRWNiU6NZ#cXgFVy^dSlsUK5q&A!J#U5jEp+oA5U2IvSSv4R2`0 z(bOJIn?qeqnN-GXI>b2LA!5_fT(AJGudWRQAP8GqsX@&EF92X7f^DvMjzOtP_+5T2 z&5iCvq(c$ECsqP#z;?KLppV203kyLZnN<37%rG87Fd#BqX3d$i|NArU7U7GiI?z{Q z*F0mFIw4#=e#18}6mBzdSp7>P2)NmC^sIcpc&Eqx7}+%Y*9>S8wW)n&1mS%i1bf(? zO0cGAH6Qc&)pfxXydq$NIs)mGFT>v-itz-fTF_uHFnCe1UIAW7<&8GA`o(y9z6G>o%#IQh9ekz#gN9s!-2&#PQAAud$emVqpQ(-(IbFx zmMq$h0&hA8Y1tWqCn9OC9e^ISw|%8<)gw6rjbE&F(j-JjLXHE1E#Xsv77bhV?;I3P z@*()WJ~}#zjCYjejGt`nU*P~rYY)k_fFxbqZGv+Dh3w74Axnk&X+-0wedQjbP<$O@UCuqILsF6bc?b{9>H;b z7u=uLMSv|NO?$cx4~Ivh|D>D)@1u-l=;LNcH00xY{;K2vVc%_stwXFJxeq%69lnEQ z@VU$=G2tFm$8m_Y3Midrv=7_{gJt}96;C; z@3D8q^#qRpV%5vU$^X*=TwTY=*q8wyWF|WAnNYrEpAa+k+(F$yoBfAUtIH z_x4+QC~(WXhIZRS1=IPe?QDoO@lYdu6t8}wm4J271DKy{pjqExH&ilKw1hX6sw4Aw z6$d_^_0|Xr$z0$CNeA{TA?H5$>~?fC>??6g8~Ae>um!1#(y%2;Tt~=~u-=0Q@8?d( z2CF`B;3)uq1YhZO5BWza^63H;x^|t;C&YKr7A;*Lm<3oognzQM0Ii`JXtDh81lQHo zNexCF!s3N`QRdE4(bP2bda@mhDX@VCKcCa{f=j+X=UIl=2^>`nS>I1=hKfN)p%6gB zXtDUuchF%=nh#lO!bE`=zI}0(coWf!aci||-C8~m8U|`&N=Anzl16~UYlw4>Iwg?0 zwzea$1L7T(D7uhdd=j#nt##d zhGT+T)e|j&>!%nu-Ty5iC1sq93g$o;Gy?oA=iK~Ygfkr!6>sBB0Oe`}?xD&7%K!Hl z9wE*yHZ%y`d8lR<>1b-`S%-BNve6nzR00^i0{u4DPylNF$KMG{X0uCay!#?lB^gRY z(>x_C3OO+r`(XPXV}k7I`~Ce4KYK(BUI$H8g|YP3QV{gpbzUStN!F^UP*}r+F(yZzX0>BI?#V3_)`tr9*M8gaA!p-HSu9@ zgtda0^=1?w1s&h`#N!GX+=`qW(mN?5pSE@6MVI_ZFw$HRry>4j*;^;w{yDlO=M_VviKPDlBOke_U`J!~}dF&A@zw ziwG@|-e5I`Mv)F2C5+S43mP=TjkxxOFUPqH6;hMP+Xnk+)S_LxegM3L`=~c5@%_!A zS!r)qqr|a+SxU3;$ZN2_)Nlb)Ri8i|j1-%yMzYhm_S+ix|HCwAQCqVs>Pt#y{0G}-IT7wBT% z0+sWA-ZI7WC>)|}EY5OJ7F4Kb?NY-^OYNxu*mc?&M?e{=I)tO513zn>gt17UO0jJ> zo#UK71S4#L2#`7$2BquB70R6KH746&j)!ryiqn85gCA?1?6rsT0sGZGIDawMp^`wF z0|aClHSDs_k1?VvVXedOaU|IHe+8<+osp^bGM;JTn2`8VQqWJhAsryt7V7}$Vo;r1#^=V9}_|wxfG9+6CE7vhL2>-ao zwC&V^hy^YzeY6>fxdc&_)j45}xi&rc;hbcdT-G6^pV5*=@~Swok7qmthlcuFdlgy3 zwp+zmw>Wj=;f~@SX9b@#_1!oAQ&%2S5rE|WC7q#VR5FXWsXFL)NVJ*-%`H|ta1*+c zrg{_oRj~+*!B|!wbP_*MG+i*MvZScL;s=^t8W(Pt>H}sp6ekfNCQk!QaCA605QX&F zadW!y6Sb@^Ea19DeDr~Pm|pB5@m8gJfs~D$a)2tbTqJPHTfwv^br{MFBZyo4Zo_CJ zPJ!LxsbVPt&tH&+^{1Lq{!m^iN0GHddx5sp*#b|yfb>06CbIr5d;tfu;j?l z)5v*?CxC-4RM$6*>h|)ed^#3T!Ws@Q*z}%k@y&cJ%suk(Swnxh7K_gWSd<^gslw0m zaQi}q>R^ckXSlRE&WS_0G|-Vql!!x8tClTKKyt&?PxHE0U64GDztXaO`*PTJy>sTn zcuo`?VuFQ}b4yRAUG7oA2aBgyiCzr2Nbg8FBiq9=b&k+@f(p)lb zb+cle}mFX>p_E3ksH$mJ(|eg=*8)IGO3`X1MlBIv+-v5 z#Xl($=pXJQBA0WK&L@0zVx-Jkj6g zE4aARi5wpXPE2IeM%DZRbD{ndBAex7s?0Gu)+ zoidlwF($iR_dQd&EyYj-9x6+dDnj-vW!kO9P-|33h>fL~rRvJu6vA-|ty(s*bjh&| zQ~4`gKgE=9QqSI&$tC69)r-PInMiNtWVuIV{no%;cxP z=Ws?j%az@nw)!PaP;ZE1USalSx5Wg-b`cZU4^3aTZdq=$KD8{h z&fNurT|c~<<*l^uAop_i70+exaLA*z0H1NN4aU>%{p1x#sN4lC68XbK^^oD%k+?B% zmE52&desYE&a{U|1jC=jys zh#`}H9%-;>kl0dS=-E_(NEwk_hF6Tg1NmVd4vX&q3P%@sG}^etshO3MUnG3#oGf`bwIhC?4a}tBoNZr zbKZ+1i{cOD;;yKPxVB<)POzCDvm627f2JC0XhbP@GLFK1OVdh!3k3sRf^i0%_Bf&^ zkOKZSNu3cDf;h){C)_DJmv%52MB|VWZItk!RI5Y~9<@tWQjYeFhE6au@`@dy)qZ$0fY?X``b%>9hF< zOS$a0r$zQjH;3Y^h({@Rb-!7M6?*mBhe4Iw2C5q88jh&rbY>!MA##ToupJd1x)SYn zmptas4&q|t_YeYhqhcB5TR%?PESyQm<=hYhHq|>044||8sp76XH_`bv1|DllLoC7= z_Kan_FFA2`$0#acWF&18Kmb{mANDAW*M@X7us99A+oK=dyYjZI><*{M8kC~;8>ES6 zky@wv9OctVdKBpb8X6kVEjQGx)}alQwStO1I<%$MAP;%lNT}J0V$d6XJeyJo=z1Q> z7oxXBR7MB=4)@Q8o2>`2>?RR0!O2&g-v3xB*-0X#1e8G6?@%7j)lUa&Y;Haku$4e8 z1i2FYc4GmhoHU?&_XfT3qLW0>J?_WH$Go~nXN>z&2}rL^o5lJ$s%98eR9wvBxkc~; zyp=HYNO=VpLwX|8!-V|Z^j!#CZ_%^TMZod1eeh3_zau(97Dc?rz!tyZwQyu9fjXFQ z7!dn4o2@4Xc|PWJ|0z@-iA@Y4t?2&TsIYilqF>~n6wVsz9wjEv{PD%*ln$rBb>l^gIZ_2ac>7`gr4_Rv z)mT!C_(Viz%zwM`cfAE5X`$SOVBzKij&m`NRJnd~Lrhdonoae+w8!9%XVZK?*SjkxN{eyDjRAEhbdXqQ4N!sHQJQu#19 z7LegH`E77XNr_y^al0U}uvWyGZ~6T;%vh$S&JU z4>H>0boOaa=qX=T zeZiQ_2$LxL63U>lK6PbXIQ%Q(O=l_UE4SP3GBDIIAiC0?|C2%A?b}myld+ig;K3~0 z*4>nqtrw5q6~05&K->6m^zH?9pAG#>P5K!tLMl^SdA0cM)G*ULm_oE_}y?^F(v;9Ht>Z zv52*H`}5&%Y`dg@TR<_OjQL8wBFHZfKt@V$&D9BT-u~wA z{Z%Pz%6ylPIAXZ2J#7J(pCtVt^1`5MwP(9)z$La=fkWq;A?+hKm_(Vf4=5>VP*t?F z+9C%->X}JHg>5q+c>D%Y$~!oS*ItCZY)LNN1(cia3r>y+(bm)?L0ZBnlj>QCdsJG~ zG)j(cYy*UY^()?E6hQa|t8<3ON^%+~iiyUUL>`4mnj(U2-A6aQIr?PPs&<5rWWLy5 z)A;sb`?KMpEjMq(TeN(R_vitst51ASjCQo=VZi$I1i_nn&RiId;E!~W(zQtL6@&}+ zs=sFBYuUxtSudH%Xv-EsgL2c?WNViGdrWF*RVjKN0|-)|imJ(4S>fa( z3Dkr8RqWiE!u;*CmTSGeAN{p(GR*mOu1!wC11D49%wDm41Td6re(K&C9f|-x5&&2! zbZ*cJlG-#UvDsLd56n;AmI03&yHCxnUArN|vW1=k>3KIYGk5XT9?`>%K5SAS#@@v1 z4Fh^G@6&1$(rIJy;=XbJZ8r=DHz6z|Zb&&w2`)Y}v=A=@Xy$?uM+6RGH#I-bX(gd+ zT$lTg9rG>R^MI%!;jS@=O{>rhntRSX?;l4hNsb*q!sY$t|Itode!W#g_sGi>3q+1F z=2|qfoL%fY9>sLFCH}hMD_rhpW%XB8ZHngH=-7lkR_CVrt0ISk_T~Y402Os}xX(|e zm*-NS#HC8)%KpAfbG69v+5=x80UkVj>`vIT7Z2`Qs@9~exzR(TY%UM}f{)KN<?&p9L5-0XeKqKG*q8G^3a>_{O;SLRor9}P!K>B%Hhn7u3+RMZ_` zudV%e_q;J>UuZG{n~j90y$zj=LZv ze`*34D~JlskJ*#O$kXZIC0o6wCVb<@jm~8!D4%qkb9T@%^0AjbIjaOA=AI85FBWZC z6m;EOp&9+Fe#DGeMdk+iBKp*Ol0HS|Ae^7sGb03@s1!&{%76nPT^eH4fk|z?Q*83hXoH$?N^|J~a^Gf2@(PC{ZxlX( zYfX~2Bg`?mjly-b?LyG#w^78m%qT0hGJHT@=fvGH0_$xiOD^GZJMJ7%- z>3zAzprVY84~#3Z_!Ux24Hp5_P7g%wKod)~77u|eeP77Tz|tIza(=YH5A2gUJZw&V zso?0gIhr{>^iYbTPq=G8R9Fn}mgfQLcsw|6i2pQ=@H6WWlZ$fTCZISJ63}sUPCE7b zJLHNSE~7Sly4&nYG}s< zC8}Lwu<3!R6n|rLk9Eta(F8Ns-KlB->$(Z3L%?8&5ipI@hFe;TM+O4-!=q`vxX0+7 z+QUSa5)$wVAx8ww8}~oiYZAwxsycYdLuD~)NuNziK!>{m)?#5rUUd{>4tV0(-H)khx*{=kkx~K zAu9WP5Y_f8TK>D>oycMVh+}fI$uaXz(yRMsx9-hwv3Ls0OO0GM>rkgEN1n7u0Ps3N zj@?2dfkcyRI)rZz?CNW}P>SC|^xt>dKbl@|@h(u>OKSv9Y5;JLdQrQ_(Wxg-Ku?L3 zvt~^FPL`@Wm`K0bVFOo=Iy>s}K)Z4Z6?ZqE)~#EMfvfCcF=DLXv2SbKi$mSSEF_uK zA`;^8k3Y~8#y~7^G*!U-!S1HY$4OR`-c)L58r#w`733E&?w^SH5s5N)#Gx^s1N>Em zZF|p-BzS3Ky1jpMUrJU7=Aq)+_2j!uR1vgHBPJkNpf~dC#v{Jo>p| z_dfC*hcN5~QIuAD#iQFz5U{l50HHL~Y`VRFdU~5OPg`z;?-RpCJl%k}ANlug zVR+aFVJZQ2U_Y`qWNCmHSY326;AksLS(YeK><>ZT#qLW#!3~yND)!%Lae0};j&WTs zrhfwS0CgB}>BxtApgcK*Sya1$g9s0rqNvYyriZGDPXJTB_h}qk8e5tE-fOcD4Q>qD zBhQXna5G1;Fe;O`wTa4h(;76(snF(sT7Z$r?Pz<&pD2rq$A>G*k*y(2C8v^*n}Bo@ zTqB7nQU`L))P!A*e!W6CF%GTLCS6d2?7%m&{JGc#X!q+#9F8)J>CC4LSh8`zCp&P6 zldNr|{pV-o$5j5{iX8Xh{;(7#VNfg#gO{jlvf})5c{ifYla@4da}5ozPdr& za-0I(Q11!SxK|A=(i<9~;ah40LD-Wf-2ZI>KVDilaGIgm$SmLDO`M6gf`dMie-*s@ zAi>|j`h%X8a*v|kzlDr}YbydjA%rOvr`DjhG9iS_q!R!yaIZTtTr?3t16oV_St371 zYI7_ebJDMw<`|au9xBhmvohxdv_MV9_MM;c$BKKDruU3RTv(_Vy|7q)g`1>wl({1? zOOI&*W&Mb51FQA}Xb;VZ3gIawMwTPUwftcZ$A_UB&$8uo#>W*81Bq6o#q~dCkJCdk zVdI!ppSL&X$9RPagw5O}KlzDC^vhm`!X=|3hiQEeJ8q0_=2rIjOy%dAxpie9%D3oXdAs$3`z7FkxH4Fo2qiEG^7dSI&E@D-30Ktf{Bn%V3`Y-m65?Tgi+xP(OCDzVjL0*l7VXP2mtJ}% zdJ({f6wZV|#|6D|rkbr^Y33CbzTwP6ZLAFHPIHhe75u8`ylbrU!6!#$^1U=~pv<{g{lfdML$mPHt0(NxIul#CzH34BQeXIA;h<`B z=7QRp`kaRHki;!kTxJa^_#%Y>LJXMgI$+ST+=``lK3yy9dVIh$i=(#Yxv8cXLORu6 z53#*7;@qKLdI~gwMI6K>oG-DDrjBli9iTq<;M>BiprCR;h;J@534E0x9vwH ztZvA1&!3;TTWx5c&0I$nflB)eNBv=P^yTyFu;`{2U)CNzJv7GfWc2!g+2wjQ)&=XT zKfBbGN6#p^^u*%My3B?ZgS%o49<&CJO3cx)xI?e}p3J(_Ft)*q7k8C4OuHdC0Yy9c zWiukKs2_Xcmr`xlJ9xNK-S)u8huggMD^0#~!)liMhrwe^jN4sJN%_LI)YRIrM#1~L z)|K_CW9G)>$}}YsnCa&tN=EcL)iZS6z*kwvW`o{E|M>F!R?vH&>Z`|Wq79x@_wQ>q zex2_8xku~Aon4_jy~nsSDHE3VbiU%FJHHan-JfHf>Z1Q3gR6GlJ#SC=9`p3I-nUEJ z&-)D@|9SAxIl0vwRdU4CY--csVjGj-nQP;FXo4MSA{#cuv|-5h+-Wb`yj8Yu-)llj zcKwOykN+-oNbHvs6}7v4wuNa#^Y%|yqV*Z#^Zm=WjI$rAw<~=fwHEr|E7Pnmc&chb%gV(tXdz&j4_qi*{9iUd*4$4VUg+yXo8S%9*^XPCrb(P6)1Q zsJu3<_|nPy8~GWn8t&ZuG417NWrZuWOYHi(3;w$6?MoVt2AR}P4r$deCd90nQY*Yz zNUg_)|AWf8^PR@tTMnrHiI(--+qQGoe8l8|6!-Okoon(|ZHfL*5{<5UoGP$@j>|uD zdM@bHxwC(8aQ~IIHJ?89Lm@|4az+Mu?3dF#p2u`c8GrBaSN1Q0FwMgwSH=#!`(;p? z_oAKu{ivHK_jU~X-d4n2U%srVQ+C=YejPM5NJk%nqe($fTHS=BD=s6>)nXb%CEUtq zPxa7VXRYGx4Fby_Y5u<=?{@e4!s1a4Y!{~~_*}Bf0Ov>HzXK{RM$#aLHTu-&BgZ53 zM{5n^4W)4q`xIv!jKi7lxi4sENusz9$Rc%D*1C1;L`%Y_iPhQr-)G*u`Q^s%mlh80 zD%4M6o-M^mcWt{fo?*$$FFhlvD!1nW%dpfRZ&q@{wWKkU@Gin25BstsNkh3gv+4EQpT~>ItOc%=}B*JTrXMHMjqmy`OYv$XDcR z+IAB^y?aMk;fGD1_WZxkP@RXkS*3-XR(vng)n}lY!X6OGes83+?8$B#-lB?%bRafN zj@xe;FJB7wf_4xN~K|z_-nzk zxG`sA(M13#w<|H~jf8;Nxik9H;$dZ}My;T6Cqi$@$Ohzi{64>pOaxX6Sd<4!W!HrS zfP9yJ2%Dk(fpxVb5nZEhs%gmdRhUgT_}?$Li9L;Fb_bWHWMh0+%cczz-7bM|u%tCZ zQp(&`D9;9}Q)mju)NUf+GYI{wINu+dC`DA5s3cKnSYlWk5Hb>dB~o39VWcsHE*A)= zI^{#VUK>7kfVUIYmM*8aK}TBgMG&;mq3Uf<|L-Zh+df%1u~xiJE5j%mID|TmV|{K} z^PJaS-*i(hx@Vq3*&nW+(aylE(3!9cIF0kf#EB+QT8lze1OMRJfp(i6ARXfj#wxe- z)(D1?K)ua>*q}nw;&^jQOISLlgc1Ut(Y)wCuY+R!WP0iUuSsNn2;6hOgpjM>e1kGy zL^}*T(4hk&D1*5B8^<*@8{GxZOrn)diHA|7@S4y`$!j-m<^`YoIJ0h<*;S_TpgHHO zFyp}1cC(p}$CdxvEH`_tn0e0hMrv~d|N64baJ&gBDjQ+?A~yfedLibE;?G#Lq3K%x zG*kTgoIQ^YIcxH}Oa%Dv*UlzH$o${0QDS%bzhD3Vzc;7tW|i+*8+2yq=@skxeeg?b z)r!9~2MpDw-g)%*lCjF2cl~bQ-?J{B$lNK$RKI7cz1V_jxu)q4)AItSE-T9#|BY|@H zJPZN+?9nhI`NOo8eZ^L@?;v9d>5xnJ_6Ou+gk#wOf5zHB6i6(faUP<=mwvLh|m8QHK-Z64)@85 z=a(B_=YT^mSJf;0zSw7J0a7hLv9vjV;fmn#*fo1!uhE^;KiuRz>YrHKt5$EugK)&X z|LnVsG8ycy{+y=|LeU8zKE6+lo~Yghn^4o$ZAe{q{e;O7Xc)eG%++%GW)X4x#aDxB zs!J}f0Blgx(mMBa9cm~J>>oDDH)--^e9)XZf2Zmc(9isiOboFpM>)>TfAp_m6k%@C z?G2C76o^hwEVUGldk_{b#(9HD1F_DROCP;y7k_Wv*%h_AgUVOCEj7JwZWk_9q)tR8#-C%jB#1Lj9$r18F7+KET0PvDMO!uRu0G)QRt@RX`;C1@UnHC(yG^Jp-?nw_E6Rb%J zCISfIAgl<;RwL}11oiMxLB8NAxr5M{gNRH99CMkDJVY(>4V0^@fdo=Q{osf^b!tkO z7KH`qOOL=AYVD_@SAPHLQ;-7;zGzF{zmLkEH?}G-B#hv(1%vN-&LO5)#HV2eE68T* z!Iu|XX1#0O}$uML{*EswsoN-fekIKt@ zw3J$c(_PizCJzp~B_R^y=A$nGD(ACMS}z!^V&FfpdSYOOd4#Xgk4B7)x|5fer=KP< zUeNKFKEd-XJBJz@MuwTY7((N*3qj~md_Wn))Vn8zx?2W*m`~aQsRIM&B6~GfbSUtw z6pyjLs&L^>PEiBr8WjYo8U%HZd_MNgeiS_1YSbawoV%(9gkQ+hBgbNw771!;u%xeE z^($|U+>wOhO~Jtyfi?3;@P#IpngTsH)VR$>Luz2&EHeg?IyVAOVr_C=06~&v_+kEw z5tXaPfUoRI3C`1q92an@%fq3g9tWuYNtIyf7+Q_9h{elk02md&-1C)%LQ}pG+Rfww zTZgeh)qjLuELbp@cdenR>G3GArmmxY2l7(Tf=M6=i+1R15=dT{1wM$2(hgl)dSTDQ zWo5O`@<))*3_<~u=9!ezGq8GEsHZh=1eIagYy|$F`N%I>Y$Vv7I<*CvTCh)g{xOJ) zZ9GyA(7sgxwsE*MEDM3u%0@8d?3Vq|g^5<^o7}sP`PNuZ0ihQkJbxP-n^|q}rMw~F z5*SMNu+WQnmcAm|N25mTCukX)#X0fH^QzbDLdO8s_se7BM;ZFQy$v;r-m?B{UTVh0 z%%wW!-YdP=y}ExSE^ejTkyoyx)CtkzUZi+Hj?nv=?U4ulKKB6hk2T>-^d=+{IS|Va(!wG5mds%Ps8w|#O+PH;_0 zzpc~SdqTeSAHMu)&fKV-4ZhJsRaH+}#a*NB6b&(w3{C_k^uy*q$2Z9wEEYGU(Mixh zVj-2WPcsSxOOrj=ILNtyQ5Cql^sj6&Om(|~+>l0ym!7OA)(>`ETGs#+dPkTrLztj^ z@*R8jsHvz-G^zr#68#E0Mr5{J98=*MWt|I2NP+;%HoN^3CIs-lm~bg$N9lun)=dB?zD7T6M6)Tz!nSH@ODOv7(J&CEKt^u$hj&(N@2MSWEzx1>^@O2u} zL-di73IQC0z-S5Ay@&wqe18P;SFnLeDj9kSfM zsb;h)@x;9G1N=B^(dmT0UI0<^i2e%AZlAG3QPUQK^2q=NoE>cZG=DWivDt)$1)44A zMav-F`}b$Uj!wn!Ai392#@G2bHktEr1mXWM3P9@#?FMZi2 zU`Z7Is7Hjx;eWW*R+>roA&4fBos7xjaZ3Nd>!;qy0OM8Af2211p^+{I5%!fp)9A?I zOHQNZ2VqR``LPyVM>?ezlK3W)bOp_ic10)zh$Jzo5eOmSCI}LQOyTm7e`pkaBCsQY zGbo{X;zHtxH1lzVL`HH*18z%<76}2lxCkBsEbh9om(Q0?D1O9P ziT*=4F~ai={N?lVu4_El7-9v3YXs{gnWKbYZVx4OK-T?K!wKk$IkBm879tB57X*?Q zW@1c2R1SV`pMA=Jnp|c(iCBc!E=B|3aFO7WGCJ4VdSI0aQw*_aEMz~@o&x+LukB&2 z+)})f3jk9&>f_x?red?6!n1`KxapXXe({NuA$=%gyBEV^>#TgCOr0Vz&ah;45I20^ za7bSF9s|)aR+wRWAI!wNZyDe{GD}(JEZ!L9+p8?hR1yQ?$9$?;YluD^ebJ=%9Z^M`UBG1y~up@mj!L!P|q6c`g zxoCYzW?&J@glQCF9Ax4bWDW9_oP3%|HAU(OE3nC54Cnz`zr)E6rV!4HYrA`kBq7Pr zGs^fOBrd~Ktq&}Ay7Ua?xDGxEP?TmU^F;GagT&Fq9od#s@jQ!!DqA)QLO4-rV1_y* zwl2iw6_(NG&N;AQrLHBofhB{tgdlRFG#4&(1Cn2SYyC28(jQJNO84OZ{CkaU# z0{O>QWjdhD>ol-jJ^tRFb02ZLieZKP>BgMAGIU9tTx_w)h&rsT@5>~~w@KwaiTnUb zIZfL|!G!64_RN{PFIatruziQyMAU^`pmK2XC&Z3Q4awO85+^ycg62V@bYQ)6dPL+N zPutdcBI}YCR3^q|XZ~|XP$Zry)<5vafFX<1n2(pvasPAfBK#w7)<1kGlS;UfSPWb( zgbRtNAKl&xgUg=Q^Do;0qAmi*^|_2iU=`XLD9+EmlBf?{WodIh;DgIyGlKj6%0dqTsYki- zhq}F-619OtNe$H+RTqmz0)i!ut@_1LPO=-H&ehE6?2?IBJ9R_8DT^sL{FSPw94pid7!d6H3i z49EVRhllU^kd9MFDlCzrOXtK2x4blWj&5R*py2mu`J@OMJ&YC((G``fJ0*z*mf(#PBHYXGSd+ zHFLk0l~vAPUO=nF@j#X*>H8@F3t- zF?vhHQcgJH`03BRo-G$;1c&H(E*tUug3EAh-ogDPhp9xr0)^s;%))E66h)-p>ch(( zN_7jWkV1+oK*9*u*6Wdzi&GY40r?#mzRLK%lyrPk_UbeyQX%Qri+o&MRh3B*ZwQ|* z>91UlgteGnxwLG%8xoW@N<+8sf|qKIiJ4l774M1EhqR&riCky7UMCC zK*&xmaDFaIR0U{vW>BM^R)z{?x24o%Xik|jMFDW0TIDioi0=0{k*5DM3~UkMv~9W$ zK5j5_rBeRyRlXhR{wZPR5nT&>)X4hU`Vcl4jUE@LC`O6kSZ0;XXU8;!Y*>Ntr1aaE zaaC9EfTM@@IW^gqLlDg#81Xstk)yslkSx||INn>XB??!X@BOnU)NNrfL!+&eHWjP@ zMv$2!g$?zq`Mi9bu5GsUs}e~qZM1k&xkawd7_vHPxVRW3T-)EjPtv-}iX(%M1TKq7 z^-&_Uj6zZr;Kv!m0=>pjP9Y~#>qrlh;pSp9rwL+}1ooJ-TS$sFs*fX5GDV-+AuO z8q{D?8ql8o)cPbY>%#Xr``d9k|nHnpy`61vj;V?<`B8)e&GRt^e28=Dtr9c5bc&*FVD){h`M zX-Q8$vd&$p{keVcZvhPE!{?)Vr0{0hjN)#+$aun4eGudfKhMRBK}e(x4mb}y2_)n+ z?uzxz%48ERF#%4TYI7Jvp{Ee*zR>-Fp>}Wt(QH!rOZ;V0mX6w3?4;;9fD1qKl|6a)i=8T3>fRVdk57R-fR)$V?x zGqI%;NfTDR%X*sb>{sQz^t;j0=lg1pt+qIpoJOV`Q~-T9NUTW%UDt?p+K(5VSLoD9 zZI4axd$ksuRokC4f3~3KIlC@-EB^giS*AAlq<11Hpd&*pu=em}k|baN#rDV-Yebn% zvU9hOama?e&i#j@#$El?%_#C95MTP9`?bnxckUSEjYvH5;_|gxhchNotR(+$)<52l z;yRE}X;9(|$IXvX1o$D2@@LjJ-q8%|2(6@zN%l@7jx_!P(gGxirFgD;Iz5)O$Jt$7 zf3J2+H&E2){CL1Msk*utYm(sx>tmE(+>qX)10r>isZH^V26R{P4bxIPn67&Dl#S*) z30fqg1Q1KaxZISI*XWgeHGO*v66_p-RiP^B|(`cP@NA}bAYW&~FVvfkV6(lAgg9@pf<^Nt*xM&(P-SW4Bi zKcHvcZTEAorv=>o^5tF5+}Usyf8xrpAIg2V4No0ql=zf>3UV)9@P9MLu*5$~rG@A= z7pJvBIJqy~zR$REp%D7h3y)!4qw*lELCyDh;fJCN46Nm1l<6plC3~)arw7s#LOH<- zqP6j7K=AVA$(3*4yb)wZ>I?vPAY~vJ{sgEZ(R^d&=4r(F2mZAAlnxWlINDY}SnH(I zO;#Y&An=qOM`#O?`R9@_@6+jp4L#@Ij!jU)mgavm?BKz^N4LAzB_x;HF?NNES&$Ee zU1AAO;YgJdi9nUk1JF`+C?Zxw=L!gdU@Z3*StLD`;egH{G>&S z`7>(=Vvej$0&I4c?kO6e%NfrjW1{Y#T!tqf?GFj5JCfIvNh0{eS6r<%r|R>3Pro6_m(~6-ODCPkGYwS0rsEv}7x`q;ioXl>YS$|k34IJ!NHVXNgmB!jwT6k?djUxS@ z{?PBJ)G^GA@%=Y?HiJDyO~y$s{Tx{H^wv$A`RQ3bN5c}y4J!&u#vmN^bE{AS0l@YV zr5!tB_}dTN0~gZiaQlP0BA`~}{oJHEjPQ0MP)cG^2^Ts{b6#H)oC(G~z3O1CKmp7YxXx)G`B+0Kb`L`D;}pu{Ky@Ut8nER(nupAc zD3^`jliGCXf~$~Iz6J%YG0Sn%37J6&obiq}S^8N3!k_iwpC`~bqlamanw5(X%foSu z;v)GVHpdnG#YydSea5o6$wOBccm|iwT~F{JrR~5T0jqng`tbg}UQBKc;S+A$MSO6W zqwE1wOTM9z{6kT3%Dj2=4qm$xTgdX1uyzBhwr6P}pSKaXJpE{l#@2Iu1DUxYGb8vM zLomz#%0}oV30TN3L~Kc#R?r|jBLJfO?}D}2P5Rc932{)<33 zu-)5QA{}@NkC5sBTcy)XFgfu!tAyg!AZCj+4BV)%IM^0&5K267oFXGR+^QTUZWguJ z7X+z{Fvg>uKqD(tGl68C@?vEaDP5h!RdDH!MuKe?<6nEXise&BeJyx`AcYi#vx4R~ zIQ#(e8-@rMnv*%+3;YVMpMI(cj76D`V{}=~9W1t)M$$Ff@wc1{hzT zn=S96e}J?59nVw-_qe@%K3asUb?5A=M!Wr3uG5Y6)}FTGxo4iuK&uNoM9WO){x>R` zet|F3%A{@NjFXX$(q-PNoF%ZBQRpZ=E*2<3rkaBJuBkeANv1*KiaU)1Ryt*ISTS@N zlwR|JS?oGZ#a3@qJ{XCDRj_TALmHZah};*i!VUn%Ao&ms9e&~z!53)f`rS1ncUlDM z)L~$fF&QgnXvZG?f*|s7s;@5tb*^I|kQ@x`d8lLCC-+M#M$IYlq|HhR%Cp<$8W1NvDU}F0GhnUY zc8m?XTv=r1=-3Yn4A3q2C!HbHf3CAWp0Z2N2(*c$;0G0@vB=BoLPHD=%na%q6|3m( zCLx}qU;%}iZB^%zV)DwWc%x>AY1Z0C09=%3BuDd6B<&Om2^s?p0rxDPNJMZqD^|_$ z)alv=C~$g*VIZukc5^M}lePp_3epZW?Ee}|0VamhRN*&pjTN$4ZeI_YHC=IpJb*VPd zZ6abZVyi^7WZJkt|6RX-D}t}>5su)v2u@o<22svk&V7QQNnyi66Kt>4p@Ums%z=ED ze(LHiP)h)2gPBp$^0oL&(_(Vv0Y0waaRpO}lbNOJy>-hL9oGZGd!(d<0*_U=p5_MB z)$Ij#rZIFDR=rcEy2AYA0%a;%Fikg*;u$|>G-dB4o3&EfD;uMimzeb#pyA|_>&0{nl zY#CdZ90<^jQ%hH(Phh1KRaI%enVMui!e+%G{>wOqQ;`L5VbdnldGplu+a_3@GpUO` zYWz!H!+n-*Bs1?Q%lyY#dzj+pH;*x^DepCY?JB=@L~!%WMB&MYq!y%uhQO0-?MF-R zF+=Uj6|2KBmC13kbjNx)Ce%g0pJ!nqL*Q6E95wqHM@1(GJ zpmeac3I1iBE+ei58}@`sqA(RHHl<>B^`j$>%yMu3k-n6L*A0AX|2kTlWPJ+I8U>WP<`XB-QQ}&@e23~)#(XBbIzLU!!{Bgyp z&-x|hKR7-)Zf2|qj`d;P$~dVOzmd|Pz0N4|v1ICm%*_5LCN}mJY*z^?fxe6^JD5)3 z;BiJ}MLzb<{l-SiPQ9xJ}8M;C&kBtHE{Z*~B(FLY}pBJ_Q8 zoVvq=z+2#t%_`HYGrnGaW&BfNC9~RiogCjl@4OC16is1ZUnxs2>Xf<}owJ-|)Q%+N zb0mQh6BULIBFMh@>mFWw*z7#zgF!+4_8j4~a;kUL8v1-U_-S^q-kEx zU(4?rMZIbH=2-`&4mTL$W7Ds@O2g*HHA~1>x8CVK+$sCikukl=UhgD4Bm_4-VCCtc zD#}yl6OBFG=IVeC5;I+ApK5h>_E6AHg6L+E!59@F7t1Pp@FwNb<<-e{A^d_~C}3=Dzo{c8+BcapVq*R8pgTYx zCSkjdTrH$=jLq2OHY_{mhK*8)?pL)UD>XAlllE*Ka%5SDJAozXfqnJD?CQIAD?j<= z>WkV~<%!x|lB!yMDOx)LTc8od%i;UgX2)o35qSl~l~`#X8XDi&J)yfw&A)+Am4?O| zl}uWEq7wDbgKe58AlFl315a0N*p!!>Ym-;pP}oFIflHuf*OXW7Px@>gA9Cd2SA)Fz zg1RZMp6Ya&Q&y-SWjexDE%`vX2QWciVr$$(J_XzM?7shC@7daWB<0j=b}D-M^l4#1 z?)6Tc%5;+sz8s@ENT%(4C@*pJatk_8cXI!SyuwmzO`TVXu}KHqSEwo$_sW0x)!?_d z@)vpYtGhc{lq_95^69H(i6=DZ!*G6oDR@em|LYg)VKK7#hG{nb(%LanBJP>my^2*e zXg?O6pNFcC--WmlBnm)#S$1LVT5~&2ZvMx&$%+mZGwaZ$41v&qwu~LBgZr_sL;bY_ zYa5`oWzdOEiw%~#V{&1jybI#v&Yrc0dy^?Om~q3QJdC(j0z|M{!gj{CWn z{Wm5Bn6i1zYSfJtBeE(r<7$1MjY?TE*Fh)v+ex>O+6HpMg`@(x9@C|{=3HP7F& zB#X?6FI9F8JJD$+)VM^40*g-o(me9%?4JLo6W_1?bA7YYF?7{ZVN!(2{OTc#Znxk* z5z2S!$qrP+=u>gFJE8*sA;h>&$d$ih%sNnQD!#?%=dl>X-lt48j~_yYbOH*|{HS9r zr=S!er}|DfZ-ZJC52DE-W~f8QjyC}muR|}){1x}|lC!uR2ckVWZc=6nBf(5D{*}o{ zgoP+TE`$&02xR!kkh;~<%TpY}&%ne=w5Y4vlABNz2oocG8|t6a&@?1#3prJ7^Zq^aN|qK}N&Nm7Gs6G3pgI-$ zSbTZ~g*c;SvRE8#S5F!{hH8+pv z@km`Q5-C17C!IY-w>VNoq{E+egY<~%$^A{JjA6+A2adyJ4g+1P%76i_Ks6Eb^C*$7 z2s_f#yR-vrD_|@$U_uy*!Kcc$|L(!RPT}5l{Mrivn%8TOq@;|S@TI5;m^s?8J|JL- zb$1~Mz!gDutQ6C%R0{i_e1P9z+>9L4TPS`vt4Lfk-g)0)O~cU!3)e~7THg1g1uM#F z31t`-@S{k(=*-9?Tg1Z_u?ceTV6+3g+082AXJpXI8e%ODYq8OSNfV_07KIqf3Kg)Y zpYtK#r*)^AlLim`n$V48$FV|=A;K2D6Er6d1H-9ytX*oP8oz%3ck~QxyGKD!fujBA z_^jb9oRd69lMw~PG)u2q_K?13)KMeRb->x2a(Nm%^D<=^h>KmuMq4mwN_n^|3x^$^ z2e87RMa23d6X>`J8*yFJ$>gdm*&cIETdnZfv-ue+&!2lYVfZYm?+-*r$B-q$IHX%^ zB-T$`)~#6hg!C>T2xWrM(ZciC0q)c&L2 z%rBSPJMIdf4q{SKkUWw*TBu$L7rxxFJY@)>Jiv`ZiSz>ykxa17DuPl8Xid|OG8-B< z{)XqQty#-suWFZ+SWUf$3JQ()D}*F{8Dk-XM&39*pFpEpVLfwhYSiqK5hNB71WVTh z0Z;4}AklJ#sh6VGKFP^J0ndqh=)tR)-ElA-6}Au337P%*>y>ZgI)$%oB?AE!5QPCa zBhsn6Y#*7tK=;SBlHm2m3eDpk5J0s%@jyZA-`!{~^P6dSUqXTKF345j{E}RhB#-_S z$#NPB^2r*cBhNoIsXN6hI|y)1&PDz#c7wvAk?=CGcR?i3eCKW$rfWP^MCgIen>k(y$h(ZQMpP#p4X&XUmC?)Z>PNru-IJ06-98W zdL%85dx_Id`GLgk(1%qp@{&55lUXhtmOQ+kEGL+LWb9T%TfK?)={=k7GH_{GB zU<5TI03P$rrh#QI&5u{3(d6jnrB6ZcLlZ=6taD~At~g2CA#{cN3XOsj?Bt1e6O|A|Q1*E1cuqz| z4vSS)PxgSsf*S1r_yvk0enI4)$e2p6ISlT4cz5SO&JvC~jX{I@LvBNPyvrPvD*rN% z_g7>kN*la^e1t|sl?WtFd^wBH@UyA9A`!bxwPkule=vXQc4{qj{y^F15qSQGq)#rJaqUmeB_7x+8_iF%5X#H_NR%`u>mO`0nMQ0B z`fTVO_5W!BM%@5RBMN?rT#2yz{x{w=%+lAtQypgfU008unFpV`EQFy^yYAE^J5Itj zA+t+Mm~G$`{~VDDr>tc1zFw>L^LF^4D~I`+pZrXhqeh=2hfU<%%N;)4<=Ok$v%|K0 zdb4Bqjv|6jwGU=({QeN60BMIF*o5R|O_cBEQyFdm72$ShPQ2H8b6 zYUrRn11HZa8FrOAKZN`IpMU=8chb7$W)=NuD8hgJYO4^U`#W+waESYkAAGlVc-d;} z_xT1*8_Z6o0VK_z|80A(rd?#H<-(aK%*_Uv z`AvQ_E4S9psiZdJ#DoV0lY6%q<$L#Aa_OKJzwJ=zGvgQ`whW+KH9IeLWS{N2CXNkz z7SCJ}^WV=rm6zV<@({Hp98zs-){FWS6t(d0(L3=tl9&G`rrnj~K7$Kfq{Ly>eXp;X zvY;yBU}(lH2VcjbQTnr%jE%dHGqmb%;6HZ?mrM(P=v=&Kd{v`)zONchb2mBsyKhUZv76G;H>(kQ#HC5!6ZE=Nn-%LIcN|oLw|uW!qU}d|E!NeiMVFBK zql^`jvEpf3-f%P9AF3N>{kWJkM(3fnZNrr`hc2BvGtF(qneT*(y#S+SK~^fTSKx>}#qZvFK=&2r{x zr9RQWT=^}nB>MdQBb9O81AX1y<4@flIb7Q}=KkqxD=VwNrY>_zJdgu)W- zPt#cYYd%b>ln7m>qsIJq{L;jNel=CE;E6}%8aCga~!Pt6f#tq zEW>AM4uMDDvBXJNnlU30kv_qK{Yabw%ylJ-6qr#;Y>xC&#%+|cb5C5ka+r$G1UC|w ze^ppe9`_qxfj@-2{!g!Sm@$(=M|V<7sr}H;#awgom`^8{%{zNa#cp8w!Z#s5a>lqQnp?cH z4{p4w)r#IBy>YhSUl6Oz*r6UBjyTnG4)U}gG>yF{gl#*lKcq8o)N>T%H?(M};r#c(L2 zh-K6hx&hI>(!TRQbX_rg(o4X$g4}Ec9hY=gTyvCpNCCun35$sEehCfij&PZAEtACs z{o^=p#6>BSR{r9Y3o37Cv_p(0-5Pb=bE45J&X@^O7V@xy#=Lrd~VHiUq5#C>Yn$eeM>E_ zeKu{*9J92qyQY09`edwV5u7ljtjpAk$?kFUs#U&TTAFpXz|L)n%aWbWG5_{Zo?K;w zEGXN+{8;|oFApyrv^2Y!d3AfyY10ok+aLRTf=b8j|4vbBalfjeg>#v%hub`5uh+Ha z5A};;&23sf>F#z$(e#PwLW==OowJKL?M? zE9p6I_}i5F#}*fA+8@l|bToT1rvB+SA5J^l{DdGipT&=&3u2!aF1q0|Vi<3Y@^l_S zzBG0?_9RK1MIpQZu{tOhl~AsIAXG}yR5e=7v$E<&<+i)W*dXK_;&mdxF8BI%AYxJ2@8 zV5>0?r^){EI9>krU#7AHm7W(VLk{jy}LP^-h5%=_|>;eL;-O7Q}1^E#y zA4;TPMewyk6mjS}$j>;$jf>`bDft!j7!;0dL&#{FYW{sPeiyKeL>v#)2!ctUOuqo)Asgwrjp}gY&Kfy_x#J6IiXpz z^rO5^rd;fHb*kZ(hr2w>eO_IBXFl%H`w{oOG+U81J-yB5M(4w>DLygp__pF!P0n1G zS>p{Bnkg+z(@g$NZ*AXR%K1CH{Pz2+ZUaYX_ED(rvMu$+E@uy$gdbI|W74%WOHFMD z*lb=rYW|_gF0P7<;OuZ9Y~i_gdFzU|UC)c^A9W_?^gj#rD_l)1=NkMq<5r!&b!D%X ztv<%Ndh45hsAH?cO_!^c3|)u*8%3&)7%P1F(fg{?lmydZJ-AEybMs#76*z`PC4d)Z3*)}To$c+-n(18@2@VA( zOQwA&PA3KBkD z8>yWW3>pn4FSa)g-57R;zwyiJ>MU{0Z~`NP6_Ll~%a;pNvOonXUnM^UU>$9Twnpfl zf>cg^DBMUo4C#$ArhvGxWf1alkRD=Z!f;4-l2p$RrnZf)wtWTiU0Sy>&G@=Z!Vtq5 zV5YRI;1+a;B$3VF9G9#*n0$atgQ+`mD^yZXhqk+R!alG|hw|>5A5>hQeX=CZU~<%m zy!eXjA(h%k7uesuh8J(a+owQo#HT>CU#@3yamT85nXQz6O4BzdetU#L1 zu?DNqwjP_;IPY}XY3j^+X&J2`p+IzqZe*onqs(^MTzIv3&xN#o~MDo1bt;+b-z z7QF;_9NSwQDL+By`Y!q%A|K};k7I;^IE%amC8dytNu`tjZTRhh1~Mj33A7=<24iX?nde8f zhU)5XBs28&N3=*=m2R3dk5o1|CWtz^{9B98ljuUkWGR!gprQByyMGSDNN_Fgr2p;7 z{FSs=lcP_nw1Dai;AWIw6HJRsn48f9!2>-WEt*s0Vs$bH<0|A(;uj_Y~<|M+oxA7y6GR92A@C7TG5 zq;eu7n|4~r%*am27D`1SRA|s7gd{Ce5>ic3RA){!q}cv3PP& zVWlrzzsq+D;vk@7RpeM#uU-vm>7{eZfVa*^DgX-j=iO%qZJEW*b)&-kHv-SWsfDb< z+dE9i>WXH}C=I^D`f`FLG%glWXKD{ zy+{D6sQRAr@pYsQ=n>GJ-P`*Ou{TSO-^a9|bmJ6k>Z$-3G~a@?L%QQo<0v939^8oo zek;*D{Dq524%Bd5w8qz@s!9* zl{LyscGcbPt3L zam6GOGqDMSHA=qU2(p9`NyxY?BB389C!2*?bp_QBq#RRaz!Qq$r65xD01RB#kdac{ zQ0xc6l1b5^c)jpV%PKpGnpdP{L|2kfvYi{5&@5nCijY)degmpNQb;tvhj2&y(BOR_ zNeJqNj1j;KI)%7~VFwB}XD8n%Yo70H*#6YkfB6H0R%Bm$b@{UHwG*CwTt;P;waiZI zr2ft?)qj#(gSzVNmbH4@X3GAnb3f~kNv^q(y6yLlvy;xQHXUGidh~kRHL7z@Zgc+q z{E5aM?VyH+n^qY081BE-{#VBzo@*xPFKSuSsQ04D(T()o7A$JHcB^kvkec6wvC4q) zCT3go15}>B+aGV0KYObBhF+OZhh6B?-=Jjin~PrCDjIMYPS-aaUbj&jZLNR&J+F^A zaVFv5=eDOmZB)J2t#(vQX+gnuwcXM)fQlh4kg5V50M7uln2Zh(5E%%BaOMM`e|@ur zgak>1`FP;g?13%n0No#i00j5M6V ztB?LgE8p+`>w(+{;j!xG@0nqPDCFm!*!$wf(17C2b?dU+&=x+vFCqKdmPv|UqvjlF z>A;MbkH_B{6om{*pE<&0%#F1h%8&d$ldj;Inf*pxOD)|oIC_$yCHN{w-lt6 zrKX(m`n+xA{IY;(o!QYJ%CJMthZ~2ze|XkV_rk6Eg`U?lY(FZuan0VF zduYP>sFi`;j~{+8%rfI}Rp zmFd0#l`p$5*;{!oVEMU#+e451YgFC$FN}8P9gQ0p7+xaG43()JdvMWxI^OA4@vFW! zbD9ZJOkqlXHw0n8*v|htm(|u>v2QoSJ2m^wjO~>SmL9@5Ajaj2XHVi(s!QhS zn;11)X8(4Zd(hrm{a=sG5@&d496nUC#;@g!rFu%OY&Q%TZe+cDNO{!Uoa6n^2e^i3 z<_5o1EG}@0e-+`;1?qLGPxivv;ab5~7uJC z`Qy#2RK0H}{OfUjyo-IV-7mY>an(KdxBGL=cJxsx>tNO(eSg|2dYGZJu6EKJc-u!} zyB@!H58A`krip7nBV$rAgki_bHMfc$Mh)EE z%W-b#k2CQ#DXY8qdTF27t{v2Ib#=-qgHM;EH1km2F12^ov1``4-xb_bJhR5A-nrW$DE5h}-bTyJ zD91-*s&q9~)RWaaXe(>usUieePbbwqL1Q@W%MZX_xmM z@el_8(ix{H`d6?B>z|d}-v`ml*ZzD287PPYlN6x0moNvBr{V#t_OI!sL=sp1P+vdB9?q=jK4FXm6;6a9wz(!L>AuEehyo?l#?liSD4 z&~O}Elu_GAkj9@o3wA?YNwWv;jQNRD1G6N>5=S^S`ahqRg=HZNjs56=+KFawqT)7p zm6}jo9UAz|kn0naM+FY=0CbKyvnP?zOQW+OM4A;!1-=$+AK(%PrBo$cu*`^S zf^Oo%9u=>qG!}hbPOI%^^Kkn~H^A}DY(sp{2<~E5-JCsZR*#!z=Vn2+!E`nZ-nQL1 zsB^!pvI5JYoe*836rE~#6!?$SCp^N495?k}WKEPZwd3JEBEXn>k1-pJXYV80FSdLO9K3)KCG?#E zbMlIdF(MvFxJHNgXM#Ydq&IzHe=qS54&GP0r1Wm=`M~FiwGpYRktXAt^@NR5)Sf+Y zA>_p*TjMpW>-N>xyRdCmyB8r%wp=>9>AA6@ck7Qm8Z_xM_HctK^*%<e6JWmO zYNOzU%W3QxZG*g2Ba+A!t5z{GCy$bVHGqYu zprFsP(?{`^=@dL|>@!{EW!h$Qb^m~XT?jH+dMvb|!-vBae);z8zNIFmuxdB2?59tK z;}X)5)?ezu%)tJ-di5;}nT$KYQ(3D@1PC6Yz+WDPTT-J|exv(frj>qejtGVvU%MCKDk! zybwRz^QSl)&j$oFja;xlBqT(wF&sUJCb-C1kcm8J%do6~kPrsVjo7;(J^9|?ea9a! zLvMsSX>s?WGFQWBz5`@W-Y{fy@Kd(tXe8|q-Gorw78l*UuR@Yz_Ka=^C?UU5X}2MK zfEL&V;{)kxLI_KE52vUN5_!7VBql##z!Z%c5kKf565%sdM+c!a1x8&ssKcvUYdiB! zXmLe40f`7sia&%|KFt`@b_aH`tCoHAwt&I#H@RY5&;Qlg`b$N-jT^dwc6&$#pMiUiS0qvfwtwHgZxL+6yHeC)m(Ry$9kX!I7fka{ zagXCPllDjQF(3_jO@f~puA>!2t58SMsVFzOu*L2r{#lqodR~{@&5bL-m*IYUl4FRj zgmGyxxZ#uV0*H}GS_y{#$qY$!EcG^F;W$k3DWNqauM?j^cO$u3(n8Y3(mwEHza!eW zV_GN(;8YyhwBGJcEv~eWN_qV5*^%N_4K{yDa5XS7zi46EtH^!i_{vP z;K+WEwh&AWuuhQlPenyC)ezLl4_Or;A86h};k%q}kF>&kc z-Md#HPkNx8BV9$&1TiGz(t)T8@HzSdU6aTB6^IL>S#&J;NF?BkRg7+2)(GmNTy98U z32wjm^3T8y(!io>xPCx^C!jcIlK5yiAV|hG z^cApF)Q<0%d~lAiLJ=0xFXk7Pm&Z1j<`IaU6HPqF=#4<1+$*!*aKH8jEXBoUo0rS` zSK%L68@BKkGJ%hK5cCu=uteLl5~Ykm>L!Uf>gua^t^>b{``dCe(!x z;)<UCaf(3>!w17Yu?+&qWvH4J}8o&?A08`gEfe$$6WcJ76946M3^h^gtyFgV^kc8*v>M6*j!zR zX!P5=QuglN?Th?~Hz~I=4Jh(g8F>#JaUF)2iYB`1TXPwRK)49U9|lMDCj*#*AlvMn z-AK^dg;al|zQoiAaPb0e2ScDIz8@dIU9bCwIVYE%CO?j+uT=TY6_aj!A^i3iS^W9= z6BxL{@93!?9m4d9!SzRs1wrG<{0$n9VYPH*9D8cNDG^bp^CQfLn(n!L=kUD?1`2I* zKi&IrdO}6si*64;w_mX5L$T7BqZyxL<;!>oJwkgUi=lIlJV$=}U`IPrmKgksmng>%F&E%rA2)Z#TMo z=tmueiG7|%jo5P2r}9*0X=$m(tyGFUv`A7Jb2?8l!*#Xw+c!IGUa>^{-@~nTi98~F z#9ER43D9_dZbvsHY+q^W>`8|Ds*58?kwCC&+R-{zUZ^c zk>)0R8`d{Ple$)x=rkpjkVTexYwe$L8AJu>GgyhqG%9n0()tb!Bv?pXfYjFvsp}iu zY2@ouID{K*A3u%*12}!81nZ?bla7(dKB9F0kNN=(5ycQtE$6Ug5=r(D_mAX06J+p? z4A~{XPt@Dup8}nyh?hV_^Jm;X)K>qQB}GDb?%ZbdY3NBrDFdD>g9>Fq`n zZ>fn_w)LHyefXeO+F$IwE{ba^oEom*26v&zji0z+<-StqviXGRz=d)9dJA@;drxH^JRR9dJyd zQ6Sz1U%1GV21I)H>Xn*@+1l548O@kEVtZ|NpkQ`j7F+eYxx`KNpnr-m-)F9_G+}03 zyOy4SKI((u6M^fICxd5zY|hN=aBbtcV{7N;)xWGm<`vT_S2X;XJS^n_DfQD|34{smDDg z>S#dqziFtw2Mm~g_eolsH<&YKY%CV zT77!;^ywxjcpyAHM#nkXzEg_58Llyv=rjpWWY5K=r5QVP;hv8#x;d|S#!?8y!T$P? z8ytJS1FVdfN0_TW9Neqd{gnz{$ac|h6dcs+b}uIsKC$xX zkt35aEunV@Og1uVBiTK0r1aGzwjaoObsABCxcDKAa8!u}K6{De9p%p3c?L-w30Y8_ zLOe1{XoO0?w#^`8`C8~fVaxz=sYgv;=`8BeKyD7aebD`Rn*X91W zMjcAZ4&V&}Ml5iKT3PPAv~(KV7#$q+ms@MF{cvaE)O&ATFb z?a1IoQn+lHUxk+5Azj3a!NEjWY^Qd4mSg|{hPsk6eY%QQ>geuu#_a7s|3v&#b+toE zPU{~o@tC|ZKfh29Wc&foa-za0g129Yt9{z408=tB#d+v{wt(8)doJ`V}Xb z0A~OUQuu8_f&L7J&9?MGnb+Wb+BwjjGMP@|8zswu9o+&KB#x zHq`X_d?a7Ui(9wmzKBH(%Pz3`w>C>xk9vRnc)PJRU(BsrK%z>BD;BDit5%H8D|0|WJii>pWH)BQY4(r1H#iT2ai9eSU!tC zbd|(03Q}n^t?zzKSX=ZN@SXB9zT$Uh6u5oR_)51*TSg?EfxiCk4iie48$ln9rj)d~ z*(ayY{WDJ2$jodPl>zMtjW{ERdZUPm-y5X$^Wu`ScbK?(qp0N(3)Qf*(PJb`9>kE~ z`=j{;VyZ*SAA^&WJcU*mU{k2ntKA3Iq*T z3vWgl&XMz+zJmvP@x$~QRuqRw=G0om2?%c&QJ4w2E;3D=O}n`ncRIr63;}~ZN9!nl zf@`ME^x9PaBI!pRC?#IY?xUwWIQ*DVnsMca6QqqKB%=-2Wb4^B3H-|lmk z`uR!7hRkDT;V&VT13vx>Ar@an4v5!@#VZ51ZES5@nYb|9>cQD@TV-9!Oz{yTI&d2a z4}$Joglde$5J9&XQ|9y|Y3*)mGv%>3O}LdL?HYB3w3@WL8d;(Vt+awC_UtTTfBO3QCG<6jq_$%TP&~07kWSLw0lI+U za)8hrqQFyCz2NIBn(x^GIJ7(XOedYaZ=W+{m?4R$k1@}f)J&dCDfa(W>x@z<>^o4UIY5c`#2fMhue(ge?UFzk7GPn zyo6+MEuPZJy!oVn;NbQ%KYc4JYd3ST-HT}<>7LiizJIqrzCA2+P1|(i*6%m0-Fo%j z8sEE7$Cr)X++pCdheeD)xV+-Uym~p22b!y|6BzfQMcW&UECD$_4g0IA^x|Un=$>U6rYQ0%=OtwF>oOp5e*2j}Cg++Tk zGb0r~V@*O@T02HuqTE4A#h9DvFO(=S*k+if@|qpb|I$crXBJh!D=Z%pjS9HV0|G?k zgAfpbeq!o|4UrX3ByV6&KiVGVG(m4}-?1ZcMkxrT2A`Zmb7%hp(D1N~d}YKwT9F}i zB7IQ!(0MQg!PGr`og$H6Torqzs2#9)aLq4Um}CS%9efgh#v zuyyy|3PiwIjU_@|eLdWt-X0i(Vjd32h>)NqOM0U^BjFjB1<%6S)s=>X|3gs)mWP9{ zbuzcPV%B`X;FlSL6ToH}lCuX~A16OY8weM5jN}jw{oOU_`o1=G2r2>4H7GrF{xxSl zRa7sp2UJIko18p9ApBM{^Lg`{nP)}kfvxaSC<+WzFTz6Ys&?}qynt&luX_Qf3=8;e zVIiSH)n~G{S%qdi9X9-1{^`iYSzfK%>};a2oP%Q6q59uCcTuDn(h-fy&(b$32sUbq z8s{LUmZ5jFMTyi7?y2FNGcpq5*bf{q&!SyCqL6^l8_BFc+xS`kyN#!`-1(zenIqti z*MS3)&t9Y2D4Wd;X4gCTcus$|HU;ADCro?#wd4L)z$LOU@2^!bC#`{B6;8cJ_Mlpf z)&lAA5V`hQRVw0QN3iP5!+M<9`U_FUoS7<T}K5v$!dzF-Lgl+w5Y6NQl zJFmmB4vvK5=k?c)sO$1U#j5;Y8W8|EcWxtzi^OIAa{lsl8qA|u7Fzx9yE{mUv3Ft> zT!=Z8!;NU}WD-Z*PuL|}f;bbY_-*EuFd%l2q~B>#(QT0FN>CGVqsJ+r4-j3LwrVM_ zjMJ&w%HuV=2=enSl{lK=Pfj!1GE7bU=IGs=UTDCsWc}Vijm4zj&syn}9db!BK(b_> z3YoHsj+a^G2?>*FGbLaM^fRpg&f88$d{5N2@+jyWFw^DC@s-Ulb^EC@qkHhhm0y)! zOh38zVs2>}7|U|hIpse#nhj_#A~FhIFow_jzE#g;61x{U#E^n?H*|Jc3*2zb0VekS zvwm8$uA?Urcg3!tR6s8y;l4x|Y@&n&^V~E$AkHcb{?=;siV@4gt*h?jhZaRI>>B;1 z;@6eY_R^7$rZznh9GMmxQj1Mp(6%40)iWCX+*=l5w86UUds%T*P73JESrE#wyXA8= z?_N{adYHo>{hKXkeJHjp<=4Qn$eNMB03vqv)^|*H&DMYYv-7g}G1PDZ=QF31&>a~M zOFr7aN8In+$_|`qeb_tyJHnH}#J2wXDW%x**XrNI!npwG9DHDDkP=>V8kGW;1h;>E zq_zQu%nmJiV~|+t*FB5qI||!6lJAb*q;<%hnm1*~)Xnc#RM#y`X?ebJWPcmy`5)?gsY_)g=y(ubj3Ia{4@%0Eu~MSS9@h z-~s3<`$EvZGfOoy=FhzFXX{m6J2?Jo$!1P69yBAt1#&uk7_*whD5=0*aIw`9WjH^z zu;_@0e8&|mBrRST4OW-&^tNTx>LQIq4kDWlWB3} zqe}=BtC;WF6E_KAgIjSR%b;iI0`g!A0q5u=wm?ghn=}k*tHg2(28T5PPU|>)UeBY+ zEDp&t8dLporkJ`3jt2Ql;aR2N)D&qE7i?9rwflK`dx;DNE4~IUEOVI2-~sy*lwTA< zFm%KT&1B9vm77$}Pz;`HuQQ>Cn2+pi8z-mb1df560U9HplmHoUy7mK1H%(Vrf`OHr z2P`TH#A60BS8e^lQB#G`xkRH~wqiZtm<2ay6Ex;xY z)N%4Zd7Na+eL*&4$7l@V4z^M-pzBRv;P%hoQH9VhOUTLoZ@7bPK>?r#VI|uLJ(ENM zFvB=Ln=R1mB+vGOB#Ivu!U1S4mYK2R`AMN(R0+AptzcwfAp{MJnU5^i5xTF{FE955 zON)t#IkD^+>_#%+t$;`wczk(IfLf~99LeLK2qm9vQKeKAkde4mkPZD8R$a)aK*D}wz5)MkyS>r zB&snK{xUW}M9fr_6cB6?gwHW#d~C~Dvy3K*p5-a80W(b8wIsv$Sa5f+hvB|3AAyfa z+BVdvWIL~~upyOC{0E#>oYg{g;ZK)IlGz87EwhZ50k4$plP1wBf_`DPRx=M2A7``5!B-e3c7Kq zWkwK+0c0^w{pd7{iE=B~Hk^_=wR{T21h^2G)WO7VZY?P2DVwA{r1iznk9Jpv+sGpL z+aCHa=U9}4ML>lVNNQ?-dA8)_L!xvcM@rPVn^t5;qO+CRnz(^?di*35(HVo6S)}XD z4*JX_ih&J~S@J?PCZ9y?BY9m|cM_L{GO-<;wG-ZJVrY%PF=2qY$lqebK~G#Kmlz6m zK2GIc7?J5JsC8u1BdL+mHo!PG(6CHK#~;6RL2YP`l|O8vZ{0&g#exKK(!vPI?0^R2 zD$+U{fLQ?dKH|8O=8;Q}0*#^&XPHcB5!pFORGwu(=tu&|DU8dGuy^6v%71W*CxBz{ zrqIfE7-4hP=vTAt;|~W-SDB!GluJ;6A}^I0i^(OfLP^VtM~UD(AId=HBeK&a=K>Fh zw0R`cvD_%fU-bR)z$#3pMoXL^Ki5c`+&VajVLSjI1+0Tikzh?3k8pFIu%`TE%PYRT zU5{O@$rfV67BW2qt4aF^^CwW+;NJj(L?3Br2kbLe+Mf6Fy8^3`Bu`0(<{OyZSvQa) zU4s1CXS=G0atKqTYz+$P4=q*~hHiIlIVp#=4c z$GTiMgz|Y(O+o1ah3#HSt9=xE{9v?^k}(UcfJ2$k%+nixujCX`emSF^($=$vZ(Ob( zXs)KCti1t2dLs3@tPXYr%Ai(CN_v2s|NQfhv8k5pA12igCXBYw8;sAmhrw@^bLYCTgL~Fg8Y#Fg}gu}gS(GSp>;&|Zj zkKvYxAFNI&n$iO2&7^@!90zjMH~=R!A?D#Wn*ly|mFAXq9Ihrffk4pCES3$wf4oHw zkE}kGDQie5WOR9a$2+J;$dbxH7y`#j^;YP2%;|4?4hF|6rN(6aConLM){trfE=+N+ zGgI*xB?}rRM+HYIYyQ=3$Nm736ayoR$Jlh3)3Ud6uU_>~e*J--n*uFt*q|%8315W6 z2n9u4MttYx9lN`J=qU*lEF~B#84gI`1DN@#PnD~$WkBYDU{C_E^Ab~16tFH$n6T9= z)J~OBR{{vQEQtP}J%9dVwBGDY${@qJ>7^%F=~N98(g_2=(ax$tg-zI_)Jo{Tp3+2H z46_0o;n)!@rwfBp0xtVBpH8es_oG!wf!YY)Q6$)Q! z0VQS;K3>)vy*u7*z#R&G3KbS;B4Je6v(NhZH3BgyDid}Z%*u{&lpq>$zc0-RbZchu z^~)D_6$1&$Q=EAI*@!Yj3Nj(TgxfDD$kAM*!E@wG(=3Cw7`XO5nvB?ODfN*2$PlX6 zqSDjvaq;s~7{!IQi5tPl)HI0$S=1UZC9>QR5wMAo(`bD}Hm8W#0ksRt8_DxWjUWsR z0d-$<*1dRaIFsAn)b!Y^<$Oc;^uAXb9UYvKlTo{(>#lyivOf+1$U+T8_0VU)fIW2Y zr=9bfO1vgcy8XI8k9oD!ZegYO24k@AvlRe0oL0OnKy1V!yy^QW56GsyVKfFV9;9G1 zC7g!)ujZWV!Y=T;zJCN`%ZsnRamZDOq{*j98La}q_WWqvKJH1O!ykDP1De5U2CG?+5Firs|f@>xLYA~+z z*L>^y>ymyLT)&eRwV6TCyZ<^{UA%g_Xca(#UfWQ)?zKxH378i@*t`j7xi6!fht>)e z4$~so?OdSKRZ`cMujb%`64(>L3U%@Mv10y>p zZn@L^bV&4;N2&jOezMQ!{60i%{B2}N%u~vPu#jxH;L7_wr|q3Qfqs=&1Cqs!-g`me ztNr=TCMS*`KagC&3KKP7r!r6_sO8t!_uTP07BSy_{uqxO{iD_wJMXI$5*sy;9y++X zO%xQOi*_~p11pRfF0caSnVe!+7S-A|L%PA^k#s&TFf1_-(8q=qA#G1#{#eJYg-EfZij1~8-FUP8e$^hF!bjmrOfY`I5BR1iWP&|8@1>V!+YdB>_Rtw%fH`z>mNUg()Y`hD#R91%#T9i z;5qsHJ?@DJa|1dNC{KsmGOQacVux6HjvVpm(FBPW)4UT2RY5B5)UI{jtNg2Uh!6oX z8SPXF;P<^1L$5>TW95pA)C{xlm$qsch9kj8yo1Ph}JtAY8gPNFZQ1f~qljj(f0f;U_ajrU)hS8b(IRa(S1_~|uMgrG` z3P8}sze^C`5NfHrcdPu|AP|z-{Sjz-J`lUa8(m6tmsZF7%ss{Ap8D!lMbX-?-{N$Z z*4w@A%E{WZ#&1Wit``_LLbb4dE~}4is~``72gSj|d5FNI-HFHRj4F=B{;EbfVV!XX zpUtsjNjw5kwL)G}AE@efBhVa09?GL3V*lk-r>^bJsh&V&iCnkb?l9_AR;tr!F>Gbc z6leD7_QF={uQ3^QQg6bta8(``MrPlx*k_0T0DvizUsKs?!Af57o@mRbLyy;`%ldzp zJZ!a2QAueB3knPo03S`Mnn!@LiV9|w2@@vN2ah`AWk})>)vk)Nas%ob?i5m0#ohd8 zv}<1)VtMOG2!-8Y0ZS?yQSb=ka1paMM#Yiy*|Vh8fd`h*12Phj%~N*;$=1YbalZ{_NDx&GoE~yf zTdr7;Z7y4EXbDq~aIO$%!*9#_g2-Xk4crA$x?t&&8fX5L=Oe1V#khCVQWBC?jv)O2F zTX*Q7<}nBgz*D=#rlL#ZZqk&adf3^L(Fnq8@oo(D_(|g;Coon}Drri(XCGTOYj&TK zi^^@zoVLIKRGXHXKCgE00~4qqWsE!~w#S2%ltlQn1(B|;$R?T_#Q4-Y^p3m%exlaP zQ_r72FFC@*z;eRv()MEl9?UO|o8UNnQqqu4&Fw~#;gspqmDSZ-Qta>@Ii@+q(I4?R z@x!&^q5h?ks3++2sGDN&E^z4H*xzXE`@Ai;r@5`M>-_SOr`m1h++mI_KDC^xwYMuO zJQgzL3bV8M7X#t&e~e9{?~8c#LU^KXP-V7UC~dy zJ``x4WkGpC>02|QOSvf-{?rR*2V2O#aWubtykY}D;9ZDhfjQ8!Np5;;Ma3`HM~#@01glr|E5-dtqfPD; z-wc?$X7Aplp{usJHEDxBlW@CDWku;S9*FW|7*kNYbVT&4y|X;y11WguLu z^txT^{2uafq={oK8FrvCIEy+)m+E_*S>ZEQ^pH#MPdAKWXChENWQvJPQ> zt)U04Z!Q@c;aARChh-5Zo{uE1(tl+4eReY9c=w{Aa4oINeXH)sw6-6<)!hvI#_!8c z&DV;y;FLXja(~g)c~@kp8NKm?Uw@8GjfqGhVh{rBwD#Ozz&u6C-&CaS_deX0Z3 zOFpTFy-JA2G|fQe+ zlA>gzk^RXP1b}!=3E#XC@y*1tEM)+5gaA;(fy;GIHFMM`m{MICQfe_ZK^8%4!Qi`B zFRe-FZ2g7*2oxh@Be<(ees5&-44fOqug&i&5J6bwiPIbW+>f22CV#^E;JJsdIwULA zI@Ev2jZ36ETz^?vnT+CuLZ~r+1~P;Pnj0|^AmnAsQvu!&Diu< z&(U2=04bbQ>t{IjZ?UCEk2}p>0{$erZN)kQN=l6={!QkG8|hjfPA<-LSW+FV_h*)q zTjH$|B@u@Et@?!BIru&2N9^8|D5Ki!ieIN5Mt;@i(lMH;+vnj~Oq`2Lyxr37WqI4G zcFg`X|MvWj<=VlYai+zUq0FZIHnm+N?I z{CO;2|2^<+lX+rDL0t}FxrT{xojoeW;^OQ@nmz)F)8_TS3ro=f$V=@dWKl0tU*t$f z>kgm9>TJ%T0(}Y)YDS7bs0ucm9n?WESPxOP;BWSY*QR2T(Zk2JtoN}oLAFG-j_4iA zoPpNu{y8maGl)3A@Z#TX?#_rAinM&z2Lp}gJ}Rx7KDUm5?Tlc($9KZi1DiYus{pqM zK;19_b11hcY|-h*kx3$xmDq%FOppV5kkQp(vm_ig0#>x`*E{;g&W=S#zE;n?vvS4r zHcGFzv{4GJaLCgBx%8Cf(#&*x!;0^flwW(9%!~Wf)#6#m1gDKrcDpi)MlVi&rd#3W zn)*oN!1d$$v(q*5gSP4nGP`o4nP*;T&c9!0UHV$~LnWxkQEP?jDYKJb&e3`?cuDb& z^^OZ0>qi`Fe{a#^+T+tzWX^@QQ^_OhF1VByAU?w3q<=bnMtb*;FRyfFMFJNA_=9%} zpwDN)%eZsjJ{4XFMNAu{c&NL{jg!B*_((Yw(;+Z>+EY`OABqNa49Nta=zO%rD#D?Z2P=?h z6-K(pW46u=AS$4;lgurWF%p>7Wo{;oBv6aE>cL8=@x_bMeZ!Ad;^fD)@RmHi7{Z&~ zYs=lmS^?NhI|7p^)}Hk=ZeoW1JKaHMJW~1!`y;9oz(IOxfrb#yGx+**PhbtSh!W*0 z_#CW_#Dao6+CA@o%0Tsq8_9|sLlklXMbp{HwMmAF#)4W{9vKWLbKlTwaw$^%74Mnq@X4T-q;Le>oi8Weca$xa# z_3hgfPKrA*ASmb$u>u^}y}QP(baJKm`PtZG!TtsGX2%R2I#k?7wBvF~(wqqZ#zz#w z1agU_L0^CrQ1acX7q5W#pn*F{@`3Frxj_zu51ZZXfKFlEgMQaH)~Ebr+SW3KHxK|| zZ34McsYs+M6I#reqdR2Tqg)YkV~EvSs(CA`81!KXfTsxRx$-u{fH0fw`0?GCL%6R0 zn{;`V%atEbjuvV`P($hjA^o=Wphgkvm_!rMkSQbi0+6?ZRQ7bty0&D8*Myr)E{1wK z2KY^zmy2kZ$O2+>B_5G3gaOefAsc5iWfYuN#7G@S+9~sxS!)1r5-$rwLQU)6;=}Me zr;__L+~ZQwcUkS)E=tYq`d%6kyDHSs+~}U?hVDy0_fEO)nz*b*`&7sBjHew1t@E+i zaR0*?g{7a`gj{|5v}LE`Kh|GeQh%mX_n5m%30}5eN1623A7u9E)#u@3V^)PN8G2%{ z&*Q2$CTG5;SJuRRCiLa|qgMSstvdOe0hH(F2Dub?n{eqhMic1KL8VQrR^xylf#!fh z80zQA8OhHofsYbqL3S6mATdW<{&r(|bh3Khl{G<*Ob1{-p(0=(=FEv3k}@imvkz5@ zuo)cBH#^BX22f#%FMYK+4K!McW_&g5N z0z&~JT*3yq%XMXF2ItU=^z`o#Sej&f5kqW1xIG*Ms|O5L;;cmj3FHXe!u>D_ss@ta zBD_Dime`DV=^P)uNJoG!(S(hoLGodSAJ+%K8xSx+AU2;v$B#c`lBf(Nj=xQT4e&2> zaX6Zk8V|<4N07n9#KAZVxUf2Hf|%{Lv0{-Re1@Zu$~wJv*}*u~LHJKN^gI@XVAgC( zgF<>Y?J)cf!!RDo>|Exca~iap5HE%xCPmAi00NXc5ikP{aj|dVhePH+$Y~%I?jVhh01X2O{nY?3_Y7f|C2u>>(m&Da}B` zO0Ni8`259-I7|Rm9V-VOO~w^P^8z5v?L)m!>xo(o)&zeGzDg#I%Dg4+D>1sD%Y&d- z-TLNh7u0yuC3|`+@og^(R!UNYNUQbKS$pMM*6rXq@8NwJU}$su{Pf z@%F{nj}1PyC(P#DIg{jDYqSqdp1+~%kTacj`Fr-y@oi)3ro4BWiG4?%4`zH7>kNy@ zUb~iDbP4Z247RgPe%H8ws^(!QcL8{?%KVKRj#KQQY1u^FQFQF$Fu{00UxvDY-sp^^ z(HuSMWOD5%(PhYs=&yINIhdY~uoC#i?6yN+769lFvM!0g18(&NOrx(yQ8g1{8AD7A zlL+w_j?mSCVTQkwA(Hs-N$M+mQ#nqhH+zFSTF?Q654(bbiUt-P!?(j$BBHh@fCkwg zC=7@nVn}TRgmr_nBFF*Z$x~=~{yv6)7``5`MS_?C5x5&R&AT#L#fzZFljHZX*pfLk z`!4HMj-c?LkK7CB81?97A$Sd*R06k2>4B@6jzL_bf0)VCyDs*FLnC`M0az7coAjbu z#NgauNN=US3J)KFz*vnaZ{RzUj^r=!^XMVWVe`Ot$uM?;_1zOA$Fs1&ujIQ@c9;a4 zy5AoExIJ-N9@9_OFBzslIy`+cKfG)MS>h{~83^J~d|-E}jfQV%Ip zT%nQW^6gCQfv*}nwpX$y-xEM6tbdE}W|@J3t4hWeceS?mR$rdeZqhmCkA&XhErhjN zXTI{5nOXSzB{i!v*Z5AjZ}u&|*?#@WZXQ!78CR5*4H=|0{CfU}aj##0>6r3l!?9h} z9)kx&DkQ3(EZF5#`y|yV+dZS%1>=eRW6!1eF60zxP=V zUbdXec5OZX;&nROr&^jF37M+q#+B{EeZY?{1zjDwXR&}mT~8;A4=GFHTN@~cOOFE> zP!Mj`K(ha(#$q_CH3Q*J*hZ0p)B$i&Iu6p!^AX{^9I)ImmnOuHh@6Z2HFW z%uVhCU+V1h#cMd7b z95Ag(p=G+cYm{X4eCO3ih;a8$-Js!h`}^o4%DccgxocjQ__n7!TLxz>Mr*o63HLEh z?=*OE1Flj5Lq#0(hPgH30!|!LBYII$=l~?|VCuyk`*3nC?&Ji=AKBUN7E55P&6Ot2 zlZL4^F!0#o(dlK z9HN+fsf zrbgP6^%8iGc>O#I9_m==HY!9+jyEgYMczDXY;KmYYucnWBd;s$$ot?hX6U?uk2Vyq z)GrGB;PdoU;O|aE50-1xSQwZO=%udNNMq~4-zq~^KC@k;k)0B;yY)JyZex!q-`z9$ zx6`gzwW2AWGvd@9H2C$~BFz-MY^DBbcp@%RcK%h)nkQ$*q!3vp5SzC4aZX7Q;1NUh zY~^+%V`Fvm@UgTS6f&e?^hnmEgm};Nkvu?!iN?k#(~<=e=kNCG_i%0bx=DstO$Sg) ziJ+C@CMRkc1Hq&&<-5$J4#bKKcPs)B2+057dlm*F54Z;6y!K0I0j)i@1etd5+$kW@tgs@~KmIz5iLTCLJ^O4Q==w&}Hp8 z@0F)6MxP`_7B7P6@f#bzy@?O(Q5m|Ln@34TULb~= zXMS`*G8Y)LNIG&GhlB_6&qNe5s$jzYZn`V1tkA2qBkkeL8H*ijqcF|WK1pugiu@-T zt%wU0C|GbV?spo3OM!uTVt&KphLAZGCXYon5s;Bg$G3E+FyUAuW*K|)a{$aB>6dE= zixSKr*Ig@(hMULsP&6Obt4XBy+2@9e+A$bc;GU0Vr9(WJN}LWokPK?ahrwUnM*Shp zn%F)tx^sRMQU#Nsm^{NqqhCMpT)9p-2F0(A&kUFr&7N59Ga}uzs4A$No+GUjLXQoG zu%bn`QKm*V%2Va9iY=B33prF01zQD_BB-|bCat#ELf?N=%uAy#&88)Rex+qYAdC*y$Vqa;vY;a>~P?D z8+VH_>m#QhD=JEwZjiV*%=Yu6rj5!!?>~BO(xu>G>Gs#&wO&&BPfuO#edW=QmN~tx zyKLq$1J|&Lja2-;KRa@Bz5PPfSXTv0hmg7sO`9#Pe7j-I!yE$#%N9|t8m@i(Q#JZ* z-5=(D@1^d@ir>Fd`}a(H>?`~^S|eIQ3bFeGZ8G`})%JeC$;7Bc0q+4Vdm|(O`j9cB zwBTZ8Mid3XWofnyoH_Fqq=aa4h|B|nM&zT(5OmtMdq^Vr)ROX+bbUJdAC7U6hjEHn zn)v~cLn&Vcj+3EAj33O--gB~myLz&Herm$F5LE)@WIikk263oiN1VZ|Cjnzvzj{ZO zQc`xr=Lx|j@gQVq??WIU3G*EOl&$1zphW^ne$U2!k$px2$-(_ZLdqBByj^+!8zV;c z66S}*M5O2Z(EKD4n(&uM{EjJe7OfEVMo8bue`_@vfQLhJ*f8VO*6dm7wh3;K>{ygw z=K}k&))zsUA;(&=1X;5@5xzb1nkc$kd8;{fU=1GCWWgi>Tn zA_z}|DO<}pqeMha?Mw2IEN}=@KZ*c0)*!lL*Opgan*WKTe%CEg$br0VP-5!a+7ztEpqhi?YKcm;)6-i|kjF zuN=fz@c>ZZbzoT`WE86&m6+$z9c=s?;~SiF>atB;mqyhXTw0;M(Zz!8IZvOCjow(T zZT>SaBu%F7|eu zcF{AUUZ$_R-OVL%%#8u(gD$4N+}?QXk$1^;-vztO+w$t)LZ`=DUj$kxH#N`RJ?dgu zN&UiO&VhG))kJH8Qa~nydM1M?!Sr4W^2Zygc&Dp-YWl?=2a0s0?NW{;Nr2t=O$#O{>c2k zKYI4YbbD>1$$Dj94*N%HX6mRw<>J_iCwo+H zG;p`h4sSK}kn``4{>Xb?EFQv5Hi2%NS6Qxh!RhDe6}r~ipF)0SW@orv9#XjO{ppD3 z$1DO$uB4O=jY`*EXA)SN_97>>OVn(ghEz5^J`5ONx77_04qMvy=5Ol(8X&mL9TThp z`p#ywZKGM{s>?7O86`BnqOFv~V|%n!yrDLU>|P{z9yo%vYFt zNIbbA>5zU;xDsh~bB+5>KBO$N5fmF+&zw1vXy10yA~v-MQ`)rYt+MHVKVjnuren1Q z=HYNYj~GX8;!%~KL#gS%aaCCuA2=8oC`>$O%L1bVca*1o&bf1xiu3r16BvkY`)P_W zg3%I%6*6;tnMrzFls502g>+CkRI#w)?%{<6G7-D z(8bh4k^;x-NAgG-lW3!8#OWJ`5YH#I7y>cTx>K!S(PD^RT}!isw>CFc?7O~af&1E6 z)nrWwB^XZ0H0A6N{U}FbpT2!}(JI%aXfP$66tz1qMZh9%fjGD!l zxqJ6wZl&XQQt757=!mqD!m@M=>vZ2Q%*g|s*ft;;+u#cQZM*_u&*&(T+F>k;2{aBG z0UQJ9iMGvyyWyIBp@Be?z~9gt$0ywfef0854c?xIu<%v!&vjXr*G%h(dR64b5Zwp> zw+IbE!A|`^k}RK+(t{@?T$ItK|1FYw=QdSM0U2hpb+1`8 zdMP)ZWSD7ez~VtM3rviR0j29XY^FJPoR-|2H_|q5Tb85T&>Zlf${|hS{`c}()c(wO z-6_BwEcZFJW`Tjoz{et3;8Ml2lX%`{BL!ngcz#Qo41l2-og4bnbcm7@gqylw4XxCJ zLw!IS`HN@0U4~ujz}Eo0HSjNb@e4Wu`H?0X2CJxF%K)6R2Xqy6BP9lHQmZz-{`Y2^ zCC!`!1RY|EApCjf~WNFT<}S+-bM(Am)-lls9eCWbBcpqzaK)BqO3E zIvnjQ_yFmX&AFRVNxoC*%`s6psg%&)Xhg9|85HuDm$;e`mp$Z9lMu7&Fye*VLgQ(c`p};4B}%Omm0a zKBWA2=A&;C9J`*3hQ#~zrncHb^yQRe@lQ_w zcTSx;d-iOdsfU!`#1*eO&Yr4c`k=V;-1ol+U$t;&2gS{Li1xSN@&3OPN6&O@ zO;fm%*QQHvjJTEO4P_(ua5b8~07? z_R#-FzQR|7DRCqy2AEj;`n_&oa@Ca5@jJO^ch(-il=@LD){JuB)IoW3?wd_$#snJU zMFVgx#->JBX#4rqVBR4O2PrVrg+2f8n>$T1Z2RcF-@5wO9JRYfMHPqG%t~F6|Erzq zl%|7kjZD0Bv}3l;md0a7C0w{MwxnzK{bA>>EI%2jHgv)5ZJ%sr-Co&d+>+o})q!2z z9ET~5aqj-6WM$Ip*A)}>dKc*`1fjQJZ6O|OONL9v8X1{J9+N@YR(mIhsfP|M%{cEl zwTsdY=j!s~C+RK7@MXztSJaxr?^*p_xc$ZAo!ooc5 z4*~y-iMtE718YV7)TCLnUhL6!{pUVCucyG4;~B%w7>){WSZ|#FX;p+sN!QmKH~(C9 zpmf3JSz{X%0|Lj_RO`)Zo1(?6>LqbIH&*;UJ}Udzm&eam`IR+aZaR5{Rj=D3?%Z5hRdU6*WIrR=5Z#RI3Y$t zth?DZvHzT!YjyHhh@;PK#LPw}CjJAJ*53q35WzHu5B-{zqbsT`!TBLxS9(eE1$uf$ zB#Uo?@{}e$l=_ms7#Tl`4m%D_8KDfAI(nz2{-KGu zJ1F|OQ{V++0b{ZrJq8ev)NL3WG;jzbYd1VA!7?(smS5eu@Dj#Syz zXb0(3x2dn&ysLKCx{+?ZJ4QCSy{Os7t&Q4zPqO}MFkQv&_4+x+_cTIPZ@2uZ95I)R zv?8Z;qaI+J+ytlwn0|1bFuAaGN4>odBF4Z{iaSvz$vo}WJX@kF$4 zX6Z{8bNA%ym#f!}UL)q{%a-M{p71`O3XaFCg2o?n{2?>*qEEUL(3NDuFLpb;x z^L+ElB(pQTZ>hS%HeSZG$PALdfXIy~Q}|~F0{TTnWL(jJ+7eF?{uy6tp!H>GCThFy z^IkrXk3(EdK3c)22{ULfD)O4s0Y`lFJ0ado$+x39RG|#P75NRNZJ1B(A?2@VE(zqm zQZ}Dj5yKg?>GX9%P>w*&6BLmB`{t!fNo#A;UcS_1W(=2_l&km!drLt{tnIw{!kK}- zGuPzfmp(6C)g6bLoQyu@9vmGqG@X|TUl01 z_@a`r!$<>3YypLjr!J*0zT<4uyup_K8y`7CUsjx{{nfpjb8cNhT*C_Oi|hgPA0W2M z996`!KCk;G)6ISU$6uMhT{3y%SZQ|ps#zr(8!x3r7J>@${NSlmdzGikyace7mS@U% zd=~*U^2>CHi13iH!jiF3oTFT^k^0u(YPSEUFR_NRa~|cLoc8Y2mGiIGEPtOn!gXC) z;lu9ZjMp0(U2}G8bi zl6WG?UE|Ub29cpiBQYUPnLGE$+>O{7L}%1a-!i`h+)}?{|w1*0c?IE$Py3ZI%aOlMEJ8Fs0XCI=eVOPNmv_}(@0dy z%>5ER0A4MZoOjChSEMV-5665a>1x?MNIzvl*rp?0OIT+Mu+e^gS@Qn zD9J7-tZp|YnE|L3Du*MHW43}aKrE~5n)iQa_wGjTBNJ%J7>Qtqik65jOFTl{n8mJ? zu9>4XWkv8r>p+TL<;<4>30zndctA}TjV$hCuR5sQ6yFUm3{F&DCt3%Y|G}L?B@O7E zIxr;1O3y!arG^jBRb)tKs_cpq*b59--AD7Arm#ZAlDR=KCFHXMYf1AjFogo#QNS{eq-KkdO=8yWR0Q?clg zZVb;V{yF^KyT^|obM=0OeE%9`QN3GCqlB|<6U#4hM~1n@f6J)1`K%FaxU3$8oDxot z`HEdj-InuY2*w|BH@kOF;SGs5ip-~M*P<)H%)&=gy&?w@u?qRxq{YQ^rp*NFkWWCx zjz@cAS&+q7qG%|!#)H&|a1;hW>@qqf;q?Js;j$*7R$+#hxPsuM2g6R$I*1*>rRr;9 zU0J03L~Gl2fRjgdqo%GtIV4>KKxnyTvJZUU7??`6iYj+6zr;{>omDh`>UM#c%EjBUuF!M!c8E?Zfw`f(-u zC8Pq98OBIOJl^`s_-RT~Qk{9(+t`zv2yDWjaLT~H;QP045-eLs3^3>!U_8JhC>I3l zWS4O=&C9?CBBCa-C?YTdH$67SeKd8LlhID)spCV^!v^bxSs|g8N{3BP-r2g-zG_nR z(c+5&ZFKbyBl)&SXn|v7afN0K?fGiqAQa$?+o~}1X@Sn=zG_abv7#|ua=Z4J-WVs(-H9%dCd1{sEkWnQw%Y~Cfc3JbB^?MpD`w%E61 z{p|VII?|g5bim7NtMXLd5eJ@(m{C_ZNH$>vGp%~okNqU?Q5H(|Xv7>X`bkPS{z*Pp5@8RM?Cpo}d1%VpnjIOr?sEsw7ND1dR3V{^YZEj9E2dPM zaC`V-g?*8I2m2zMM`S%rf$Q9v`4UT*r9=YE?JLbb2%n4~UhdsF#@KAOqtwCtRGw=y z;uRE$==66lYm;-@9sO6P2q#!*2ddlf0y@V)n&~!H7>J1E}kQIW8Ru4AHp?^M*1TKl|NWtW^Ku3X~ z5D65Efi9sZ;vSS{urK_$4Vm%2n}32C8^K&Jnj~Nr$zb)uBkkf6q0*r8_wRKTv+xTH zrCaI2i=(fk_#Ab65j-^s5Nwkl#aSk8KFzO;UpagV;ke@Eux|ujv79f^*fG1_PXN(=xyPd-lAzJQqMI^}V^P>+NO5q4Tb=ZAEP; zD;mXNk>8i_);JM347n3nGW7ux&v4e=X@^wR8zkFMKr38A2*n{Z?) zJT=t;7OmA*{)m|ta;3v^^iI~~k>0H=xkL55qI3ukgEIk4YzYPR=d3V=$OSXG;3!l$ z;fj9&Y%YGB8uPKAF4ra}k4pU;bGv~#4fTu&3{=~_#aB%n(dcjX@1MEjh!{KxhH+ta zi|`1L`R6p5WA}=?*8nh{7-21dEM~^*IJ$$e4y-_|Jc7N54 z4SpXQZ=8-;>zK%&+dP%RM~Z6bA46ja4c)Kh6&NTRmrG~}ic4ry@Cm{;Au(fU*M{D6 z=Cepx8f6P4;zZg-N~^zV1{ZRwh?#2h{M5q(-%|ok3ZNsjf?H=$O$W6Lx0}6W^Ru7# zOzth60t=hHa6Y{#Bih~F|95}xaQaqT?C03MiJ0#>a%9BbVehCkMJFo;PPB8B&JuCC z>gK8~*O;eH!iUWDd{gya>-aDflHcLdt}eW{Wq7@BY*hh;anT6yJm!`8&`x^+j8`fw z0V?Cw6XuB-s%=o(L*hRJ;x}CilnxptsIf6)0yx-3bi|E08hqea<(t})_S>wknL;}I zQ3+G@NCSmD`{p;sm_9}mp@oq+oK&GKwH_Fypxik?iOGQTgKHmki<->v-+zP5P7B}+ zof|>JeA7;6o^B9x4p5f?7g49JgK|)WAe_Eo~aOz^zV-gGk<@qJWy(To( zqI+FRtpA6y^N#DWegD6eJt8w9o0KhNBwHauXjn-^kp`9OHj@!TR%Ik1iBbv4C?S=M zQc;vdgGfbEzvsbyf4`6KpFjV6J~xf)eO>2up2zVzUPGAu^uFY^1kEtfb^h6U(p|_V z;4Rfv`P#P7nWgbG-S8&w+;V0BcMtn54OLfCR=&6}ck9-zWP|jk1mekZ*$uIR<3pjB zw}zC$HZi7g4KhYzG>=iXN>2zZFMPljqf2VR*KjyE4DQ>%R8$tdgf>CO{zyLi#fwr< zBlPWnm4{TWY-xC*t~UI$nK}tDA;j@F1LPVADPuY(0#5bS=M4-=+yJ1aRQh;{Yzva6w`C$;?y^Er?oH0l`pln8rYl z4ToA){(Y>A(Qc)6ZFG$z6NUw|G}y%luYWHriUpAW=vFA{I>6AQ)|J2bs|*ASLKvCP zE4Un|3u%p@^7W^&%*=pEGw#6Bk+PU56h+7gMOR$6c(H`A%Nf%h^#g!4 z?)lr<>7e2W$(3`N?NiP&Cfi~rGH>3aCr{2Y-#}o3E7306b|eG6>3xLfK#l<8`ipVB z{j}^GbAsUqLK~Oi-ecZ88U0fcc7=h&c{p#k!kPi~Q!gBHtUT54NA1?xFug8Xvd5hn zKA=ehsySNj>#HK#4e&+~ZBwW2@6n&<&oa)$=>B&}#oFxP!1RJU?@H8LJ9a4hXg}X@ z-Q1hLxyfU<<~{3a)L_p?Xap`F_K{f;vcMAo6DU+3x`>q(4@OZXz;A!*nFik)CmCAH zeTzaYSc44u&m@LAx81D(OxpZ^5E+(PI4#7Jgs#@_SnRjEbGYb38BU#{Tw_ZjDn5!hh@GpEnhqa zp&h3-u$iuss;P^KWbi0`w@xlRMLeqAZMoE4lrAClyU6|E;RU0&sqb>N$b zTj)pj^_X_N>=9?*<=Q|E#}{9*4YaW^^|7)kKfvc4x|l{(u@rsY63F@OK?K!!m@ zlKK1IGmggsN8O=%%~YRXGXd7%DVL{1k4>+!X{$78_R4`L(yy-yOD!K8?bNDEyLgCC zLE9D1DovcYEhXgSYwJ^9DX$W9JF8mP37p+vQ%rQD9?^cElSl8)xf^4msXXf1Ki9

sCgeo=(xX6J5K`tT>rk=lYy0*1qxc-dcaj_B*sI zwd|{%XJDvNza~#xwSXX4)HdYVB6SbjVf}jhC9QUuSvX*TpJ$}Q%YyTtFRz+;I%7_D z#E}n98v1EgA=SZ)Rc3ZsnpV9b_(Wi+y_V_CyvVWH^E^HlO-PyZ^Kxm3e^j27>z?bOVYoNjo!4@rF9o~iR){b?Z0!6zNHH7_SW=(39)LaA-r52+8><=2C#3CJYc z!XIw6bF9*i&3sn4b64Y<^cPdA{e}k)xtwcR_q^8n#W$1zL>+NZs4lK^eVblFO*5JL zY-s?U;H`Eou{h8~@SFEtRHa+;?8Q3Y8*!cdZ|1oKklW^<5vDmN22ZJ}PY}ZiXtf|#JN{~5o z{DU9b1>}wX!(ot#+Wb7QGn_7eT+wK~KdG-OZ5#&_MGqpSWfKPc%S+G+G@pjiDC9h7 zfYFNvTv8oh`_t>QtSD&bQKgQR#lqf9qbS4F5Y()Y@G-A>w(^k!@~u;PPK538-xs^pnUVMK z*PUb0-7G{*Uh{ENR;McmLLkI;a57Yj<}KJ9%+ztNCA6RM-~w`}?h( zVxsc4=+Ay;F@EKZ-Sys1{9XHO-F9{A?4P-2a^m%cb}qeJ4pN=JnLc6o@W@{l;YKwY z8MDnV=LRGuys|BSn0#hzzGc53@gL0Jn~o^+R~yk$zw`SyuS2f%^Bo?ax`g}(yH;x@Ht$%gLBg&Q zm(s3d)qX_WA9i}*{5GXO&b1i1$mVOtp`P;sPW@2d5bRPndqd~$j*kvjndK`N9PfBF zqxhD~*pmjfiOFZyCTcd(OU|2af5A8^(Cdb!=NOpsVRa_Zy|3(-ckG+*1fTNRPl& ziN?2hwQcBhc%fcB!s~UO*6Os@80UUTS99mqHkRm&kLytRrfz)fBxdG#HDlyrw`tK-uuL*#L?Hv zy5DP>wWj^>BST&W+_GEOz5c>@ja6HR_KdS!JA02wX=a-S%_r&9u?ubP``YXCtTyx- zYN~pJ>-#pJH1F!DqN!f+=i7gG>M`xX=PUl_)mkli`e}@sacV+w#Nz(X=Q)OsDmoI< zoy!_?uF$?RVe*_dC!%|r-q>`zo>8XH@6mxZBUX$oYHz0%>}t}vU%vhEVnff?Cv{#v z8k(tY*Q8D5h})N7Es=H7QUpUyVe*4;F#>6Cd(;~u$;j;Lv(+sR?kmoa_|UE*h@ z&q_FXJ8?zI_VG=fy6g9Dwxs%L-}XH^t^K?xxisFvz$|jz{JCoSd#e<}y?ga?scxKm zf7wC<*Wt>?L%MnWxL@+=?2gH$DR+Z!Ex2;{dFteI+wJlyCamo>WUyyq ze2Z^Ix66ty^fTMY$h^hvV_AcyE${zJX^_?cWvjMrzqfyItiT|v-`J$D3v2H0iaz1^ z`J?8t-&*p2~@XZj!P(cGoH-J+Oxo$H5e@`#&ou5|a4(?#l9 z_fA$^GBbOr;8eN&n_Y~@9=+n^;ZrI~3r+hSRXh;;%q#bMNqK(o?8xUsv7U{LMTRlQu=e=@xhWtz79drnQjzU6UIbFUHeHr}OQ`g!N#Sp#z;*Yp_~=jBkU!C3p=e2XR7 z8ZqYM)9hSJ69+#&aoaY;G9vTG+dIA1y-L^m8FRhw>ETI>qGru|FyvRvTfeili+rp5 z?7Dx~Ys}*H7fv5{woMy2z^Y+@tzXZKxAzOooXJ~!)WkV;;Na1IuRrbc%2A3v;do-@ zwS^6jH2YX&Sbei*V-}#JGyllv%5pf zX|G!!esbfOK3~{sfbk_=Wy>GWBl~$&H0!pZ(#>|l^1=H)FPdRKK_j%syMEL56diw@ zTKJ`>qQ{KD=Fe7IefavjC%&TqX%wWe}|r zt8_SSo4wVbIYz~X-wG3=23;JraJI*fj?rHeGV6Iwbp1I}xkyv@V#1GeONNKOd62S0 z_q*4V7yZAk8DU>5I_}=b&%Zl#I(av0*D_tJ#Oc#M=}%rT->_j>!l>~RKlZ(a#5YT9CIt5zC1g)`HJ^tS)tlw_p5QQf|Ahoz=h zS2TSWKF4|FEQhvhr*)h9CGP2~q1~#sO#RyI+>>RKz0A*Ti!UupuX9VK@qH!d!J1>| zTx!<;?~~kqX+nqJgEuPFZZ&nV<(H_p9bf0{8dK$V_wDXyUp7p2X!7y*x;?H<9%bwq zytLDjDILl?e=O_M{p3W;^AkK&8fz)tYr1~#gl;$9{=#8YhOxpoZMsAAUcjE%qla#P zZ&-A%pQG`*f&{gs7Vk7_LQEn&A6nmk7FzGpnTrp#I_Ye_Td!WdQoEBLuNAWs{5$Te z=M&sFcej7k(Ob71H$L3E=62rfb*~)r-uBXPUp+HFW`3KZw;|4{EnBtLU7t45r*Kjy z^|1-D&DNft+N!Tj-;c}FHDWf6^uBj_#Qs`q54OT0CmhNLwwH=IZ@}%%){G)5{#~^=sp*`SXpdeR2!-XgIEUukreM zg_e5rQTtqebr|r)DDz#Nf9u}c11{cFZ=;;Q?CSnmb^VP^g7(jvV5XD0*=>a7x-{=w z)w9o^Zgjr(f%COZji3GQez$kiaJ_CnCN<2Pz;Htggw8R?qqi8eZTxuJ9kNi#M!#um z-+r1s8F0xx$DsQaneE4D_fTz)E;xwZqk6lfvQ&{-#48%quKYpGyI=D z+cqI2aIwh-UG-+)J#r zi>{3MrIwT%`265Yjl;d%qbKd0lCv&OVb;9L*mF4+L*LCBoo%=3bjtVgX6G*5KK}mU zf*ac>*<6U)yzOoOjFF3+>blgqdFAT+9(m1%`Glz5zcgajypLUu{j)FWpEzrOH4`wUAfd3s|K546<%&D4|oSAOg7+q&)FI^K2qo9;atUMPC2 zzkcMW@y#tyHJluyysb%U#l+c0hC3=Vv#Z6P32>*%x;jX$xqBP;i>K-g+PqZ#*6!j)2e+byRc*ytCBRUpK z7EM=f(c*gTMk8{stXf>sX5MLotEbPbpZ}p@=b#%CKUfSHJfxe)$2oHsd+gFZcK>2<)$$jg77i_+S$%Ewuyqt*ruH`AZyA##=CMN?^{<}2Mqn&Wocipe`fiUiDOH88GKUMzehVOK&9DJyZQmy zA(J8(?|oMOzvS6TyF1QwF;lAB;!RzpvE%pZzVu8lc7TcS1WfB?<6Re5t}4hYym&;TnU?RRsPC`Z#G4QI^R{g>@2<_lQ{Fur zy~#7*SiGyQ@1^J7<@Ud8y}fQSS z(d^dBPgZDJXIu)8)(`QEjgJ#&K+C1IKlQ*BhuP2&R34h~&|0G4y1cHpF3?LgGNV+d zcfv=L(b+wo)_bp+wx;L#$6k9b*~aX6arbsBFZaQt^H!M#mKXRRwBM+e^QqFeWoYJ2 z0K(4u91D^?E3eo`kM^abvH}hAO-=j$LUW<_n`IlmU;deS;cv^orOTW_PiyD+XD1t6 zZfp9~5x|u^nwFiuy8ZL&ZA0tbg*`PD{uOH|Hr_d|BzH)UfZ-Dioc@P@{KKPV(Enf+ z^&rgu2WI@={|~Jd{N|d^@xa{6t7>-Ty>gwYcPD)Q5w|q+0@os^$o|A45%lMElUh%DhoMjGva1_MFETK=C${E^D{P$y zeTHs=MJJ({5*O+E>_`CYKYU#v+J0S}<#zF6D3f=*U{C*cC{KX{s5@c8{fhoI?&r-c zM&iPVxa#G;h^udT4A5VLGpjK5Yq{%;c$O^M_)bBxU$QplHX{|S_N!3yCg=x$PmBMa zzo5Dzcs?d9*h(9n=ow+$BpTLI9xx$fhw6(Vjsc~}A09*P!kVYJMfH;(gC1BhLkHn5 zo^qltNC7;21^4^!9K;8U?^)ERtE{Eg`)i!hk;4g+sWjYDtJ_)$p?gRpx^kuDX0uv( z-p$IHe!$&=WG*D#;-f=O2JO#1{$bh=n=x5_;Q?h|u|>aRxY|9a&qb?s6gjKjfQP_{EKnqI=uYrT!Z%#5(Ki>ks$1yt1X;CCyQT%vY;^YFpBxY-18^ zk68X$=m1bU8W=g`EMgWU>`+E}XApA~UcTvBlbq!oKV`Q4zM3z^pT>-9Wze;mmtw=7 zii%fN&vYwquJ)>n!o*2=E$f|aSf{O18^zkSyStvP@E)i7%xizv)Z}x$Pb99`kYC{* z!&t_TwgI(s>}!q6m@sJd+c2gVtqtrt^1r3kp%5K^N{A zBKzSMi`5eZGBLTVRh{ov?GD#h=I;!iZ0zjba}1CHe3XHiNFtjz7cr-J?=s$b_x}Ah z{DCkL5U~^dYtg-b)v0D2@~)_851x6#gJF4-l?Xk0GeKY@M|L1Jm+Sr4S`0%qu~C8b z#`{Q6*CDtdL^3yMuCfFUHO4oJj0?AJt$RY#3VE0CP+0xiHC034{0YI5z!0u8Zou;< zTgG7siuAK5BQZ3NOq_+@fL$;1^v1q3r-;!DM;IhU(U!vtg?4m5|D;%(>lmcJ8qI8qk0 zvl^~zAGA_zgP$n#<61BPM7Si<_dA>G%IqKRhnPvZ{>*D9NhwhLaN*>_H&_-jIu?dN z6{Jh}pe>2~cd+GzqbLT{OaVn!%g~Oo^RCT1)7N}pnkVc-qVHO@X|vte zw-Zm0WJj^zWz;W|b<|*JgInPhCeHi=m(;>D7oqDi3yUedZg{ccEJKnTyVI-8%rKmM zF>iQ`K3QU2c_$c1iJ=@cS_zS0^pDHhI-ES9MGAfP^sEw6;Zdb&tCF(tm-PpO=Iz_J z<0NuS*uBt_?(y^P@H!FXPTZdtPIJ6QLJWY)bea{(IL-lfI=lb%^?8l)%oM^bD<3Ap z1je2-XU?nzPAwt`0-I(+SmI0ACI2W2iDD%;;|sx>=+uTYHy6_wq|L-Wi5*cCB3oE9 zD%!3-7&&Z5(y!8~Q(U$6s#PNBmjNonW^9)5SHW06Y~8!@V)!N|93>@+UwY$c_#PfB zvWl$`c-J$VMMuT!Cfe7Ml66pS#4ij-10kY9%3(A4hhYbw>uP8XeskYAg4f|q#R5Vt zvjkoe^wLsp*E+^OaH-sbgEgRlsvBL~i9AnMYKmr0-bd>=2-BEUy-H6f*0Z{>*Fe|O z3&xKU6O=Nuf>+PSdULA2ewtoCRk!`@{+AcWBtg#92V_QMS4+4`97Zz4#{&MNi8bMw zPzFz82yHw)eej7y5cgV;UP<0rLTm;8nnRr^5`4Z(_yLRnOSeuQ;Yxx#gBgAf-_|$G!Z!_;IDfYsg z6Yg5~?sf6RgwOX0V=!J|oa4nCgsU>FUu!4oE=-%0BCmzTmFvM~pJ^dI;GFx^b z2ta?rUp+kDF<1?RXb3Y~^q|6;kWFm$>V7-|k*VWeGyTseK+1QRwIZ&bR1oNWWii48 z5P?=!<5diV2p#_v@p#^(SyrnXj4Lbl5AlD_D;G!+y;K?>@eQV)@E|e{$e+ zF*OrS9{huN5qfjs=sjD<>%g5g3Qm2zh*Vmby!~-st4|@O^n5k8O2{rOpapV=6ktFT z7d{I6MRDSTAfk%*ws5qefC&MI^~(lf_V`d=oFTqG?iX^3FvAmx4Y!QrXhGN`cbOY6 zR4@GL(0Qmr7={!3ly~6rqG+|puQ=t5jE%YfXKvs2`|JHOsRLdP4VyJH=QPEqLEJx3 zha{~IiGF}n6KXLzW#I>ke+KV}1oOcARAIXisSl3-V!O8GM}N2fxByF*sA4W7l3X;N zLQKUl?$Q>+e~>~F@|?`$*oF%&cNA^vK=`+d9P`>pd7B!tSfBF>CQ45j@DdV&v?dgf z7C)Erg&YBr`-a1I#QG#FD=S&=gieWIb?~v+HhpvyW9KH3SJc_r*;y6=lt4VSc3*cQ zR~Xs}Qg($Ir$v$QDa0IRK^j-_u3gkCja7!ZdOR z*hOQ07q3Mcu$9vZKK(){j(krpd;M~bFhlccl4w?CHnmH)s;zSR!C+ERQTdo1qfHIY znR|esZirVLAP{8WHhJQH#!1f()UiQ>2Jl0Eyc>lpH9;cqq$JYOZat(IUE~3^V%;)Z zaTa3@MYbdKOoVW8W;oOFSmk+B{!4+eK1wCrXa*ZR-+veLG2SN*TD*be6EWN6R^Uj; z_dsrUpWZ7MecT!UY}OXDbXiiUI5?-43_d0fgJ~g)1Bp{$ZF0>J)i6fiCL1QI@aOCo zY%KGP+@qt%@Jo4QxYx6f`}6GCIde$nggZ?x&7O|KXZmzF@@P3)4!etbqehKt-FW+g z%iHn7B6_;kI<(V-4M9h*jY};?7#zJwXC$(i3XaTqzJc9V6dszInnYQ!Drg2?y?Q0( z5MP3C;Ic6sh43R=)Iz(*zeD2_Yg6bT&!0V87Vf1$n$ix#AaiQcqlq7kKM()7X2&}W zeL1F4-z8wk>5^Hfpd(CgxsGt7L`lK=n@f%jDak+7dv~+4AQN=t)tlX?H7q??$9HjW zWLITWAV6iPB`W9!$~b$A-W;TD?N$xYupMr1Z$VrI4#D|#{H zP&@osty7~rsi|!VIpNzVL#RszLzv@(L_3w8p}685S`Ptn5Q#BV;~C22RQ2kKeK5uzx7Qe zFkDtl|Ni|YV`vkvIjf!8Q5Pu)7QrOjoe(JqTw-X+7eP?u5W4IG z+-k}EAu4awn^Dks;(i%ZHalV#22Jz>O9@6JF7bMtd6@P_-blh7khfOq2)aS&OZW|P zaE#zyv%9Ne-+9IBQBo47>mF2qM7tUr8`}(1>(l3gOB^lLz?EqlmLF zh&`UTf}+P$wIL>N#sQoA9@b^66W%=+5y-nOnxuB^D%@4pBs4v5aN$-!mbE)xw3jc> zJXFCZR%Ewts`HfOHJZHMs*5TR8tz(U8X2mjqo`Fh|9S`BE65!p9b_FqRJ?H5j|>Yf z-oFiipU2(OoaDro`J4zWBFv_()#9iWb1fnwW4ojo8Z;ERap=eS)4%YwZ_US zZpn>e*F)u6>}kBkoyZrac0=(nym((ku7C8LOuWwi4LohFl|5pX-md|e<@4ThXUPQHhDr=qLJ=*K+K!zj=3-FeFI^{DH6nWzys6wdCF+OSS{x?oXs&v#V>uqg=Jv;85Z1cR3o`X1! zaIHlU;n?&zgwgn+L!{v^ozdkAIt-q(QR3VJJ1y1^nM^&qcGa2ge&sDKH~kNsVH7d7 zz%f!z*TV(#U(+!kUtbSO8x8@KLiYQ00t^Vb8)fgu&U*Rg=Vfp(Iks?fkz$a`2UggR z^bM6SmHrteoNZGq!wuJVZPKL4grJx7ZIkBCJ#>9>z!2InJ`k&35f8~n%e!Iki&2R5 z_*=K$|I%g2`jM!?an_%BC@k2-dn_a-wr5)en$4YrC5>)`$GwlrAD`#x@X9{=q-SL0 zeEj%O+%TeS12>vNJ)wlhZ~$+%)nyS^q3*l>E}L(o{}dOz;5viZ_j%h8DDp`OqV}LW z0db|^$G@INrovDxKfF-d7liy+3ck33_otj5|eKpPv zi?BaaTvUX42If$Mp|}cToi>zvJ3>p#009zYxCOU2jpW>IJHOtHUJ|p*fx@EaC&6Ss zKt?J(0-ug&S0B1kW_iG5|E_=X3~y!IyZ+K#P`;NP<7;6^jF63O?x6;5%qIaI*b8n# zy~=^H;nmHjuHCwEfABw~i%bF^h?{qlO-!t?xcUw#BZPQ9c5G)1V=>!?AA3!?pZBS@ zOW2%gC35lID&L++N(k1*fR=P|12tZ~ZLu|VRw+5%Y>*VJd750#XTU%dk)8(+D&a}ZwbH6% zxY?9Xk&D437L4NKs%3Znx(;HzFb=0&;?W3!LA|@;#rfIGE^ejTpnbvyno5=wpyePj zVmmgl{YD(g;$C$6n^=Ucj6Yf)yv0fXh`ZL7!Vb7=0Y>Ix7bvl?6ryYmR6i0lHfBsG zzCw)WfLSQ++u@Chm&y*LkJMxfX(K5aA97+pZY4 z^)=!)YJpc*B$OU9xr{GK7~{vur)P!H&KG4xpWyYe!6Q)=u@rMk}H{oM_blyLyDB#3h0X2Nd_wVm%$fg7s9Kh=b zTh%L(k?o2f)2vbq3#tiHC&|*!bJaV(<4KANmK7dPTnrj(l1&MmKS!b=)r6#50dpX* zY6`3NJL!oAfOO);;| zBxCMB%Npg{LEsIAqFBld_tI0SytTF_Smr!C_pLv}1d9!plQ-pv96kL#vJ{*aq^ zmLh%vhTVg?eT*LJHRQ9V3;II5DMXS4h|nYdi&88w>zvm3BxhA zMP$80h?<=3zz!wKDt1oU_^H4}Mqu~p*>-#yWx>(83C|7CkxV#z8MJOaE_`0m71 zaG~9x?^A6s8WBflN=i{EaI}{q=R_RWKjQ@JUH%$y5mcxYn*(`801iva%Hn_|y}Vjc z8xgi}j(Z_mD%xlO3<*?197^)U>-F6xj31v9({YtjW$^IR2^cQS{{7K^-woY!-!k_s z+j{xf=Cnnd4`g@WxZQ5!N8>{o<-?CnPhIu-w)wfs#b3OyDMXp{U-W$J;k$V6;mb5g z^%eQSQtD=yyskD|>^)d(R8~Y%x&1=d$SSKD!8L%m{4q#1s>hj|5FAz%MN?ywpPL zxw*4xWN?U8$Bc~C&d#?MW`}`i!dxkK8U$A;FuR{t7nmHDMOJ|(g8>x!~B zPqH#RTj2Q#HiK#JY|FmhX~%+JU;13` z@+>_nCck>cr<#a}*T=@x_&Fy9f9~zOH!L&#ZSjNWiIp`g%3oJ!Nf2m?)LHN~BsM8E zwLGSOEqbz{n!{{nMOIA!*MdOv=Vd9k>AaqXX5Q%o#k7P`h93wxUW#VWhx+3igU z=U#x_g2GU=t#=>Z(Y}0E^qa3q1vk>a4DVNCXr485M?`)^NZ620Sw%jXFWvg3ukBgW z<-)Ih55MH*-Um<^ffKoe3a|y#ym2X=lIeDHy|um7FDLb8UG= z&5BK+Gp^M?Er4`als!0Kv-eF+R>Yg8374viE5CN>&@b|a#qZ9eD!b=pfA%YNj!!RM zQ_`il=0tiJ@A9@-ZO_&y-O240i{q{Jn|XD1sHsg&Aj8E+jz2fto?Ts|RJ%s)ckhOE zs1ZGv>;0)A4Qh4!ny=Nqm4Tb?RF^*KhyMI5H|1x>S3p$%`%^vl5a#U;G12*tzrE@E z_2}8oVhjKGkB7Drbpw`5`b;Xz9UL|~ZJb)0BkaFFv5Vb?xQ|xYB^}Z-7Yo-{$Zt1v)0`7iK3xGYgv<4)_99}u~DZAN4!am3Zdy^a8mI0 zNzKd6ITQm#L|u!B2&L6yg5p+DhGvP0hh2L!wmg}ZfL)0*wwYP3Rh|R^vdR9^ZgP)j zK4Sg*oiEqYn}V%P8}2Mm(IckysumBss4}X+#ev#@v~mlOEFA2a4oUVL$+a&nKVgbZ z|4aDZ5(|q4RhoLfcv_4w+1zC_be;!Zt2WXM4rwWjr57Z+ldU-4}X%?u7xzf4;29M}<_$+ss-1@k*pdkl4L$fWvni7zzlO2otTs$|3 zR--tTKn&&%fatzjA9(PTYqV#L@K#GnY55OxB>8n9F}%N58b6l)0HHbc3|^+RQoHEI zD0sLKoLh+_4FqsS)k#?gpe98XMMqGz*w+*6M>r&>5pz85xy-4U8(<7ZALWHn4Ff%b z?E=0L!4bvYtH?7Ng`;Mo);d)?g|FdG{PB&DOsZ0|na7NFFOm1H6DW$0*u z+ZYTot0!Q1Qf6dWm_O6#oFAc8#xyRV>{NZdM~^nScA}gm>qWpdcv?I;J8VPL7c)8R zVLx;yfEcqGa2|9z0(@$o_>>;jn+6zAk4pxC0~zW}d^#&{Q2VAdu*;~V=7j`EmqKG* z7yB4Jy(TO$vM=X3H5B}JYE|Equ^3s-2#Ox?zA#O2ALd4LUeQjv!EB%% zlHhN_%M8PAF_07116~l^Tgj#(JdavRrjML&1lzS?e!S7ii6Nysy$I_RqCgnlmDmp+ z9pmiaKG%n;u@(6)SV}ymf{N|%Ga{%JUkBu1ivcm6w7|HM`tV^zmQ$fdN~6(?8+kEI zqSkNcSMj(|N5cuR!9<)kh~O~`y!3fl-{s_N0p=ibg?Xqgkef_7SdZ9?eHuFKLR8c- zwEkNte<)FZQbYp!!GpkPX5Y-fTuj8@vN0I`77h*D0ijAv_1ja_@6)b+$i@qRVZpCs zHckk!IK==-$lm8zx*}+vM8tyX&!l8#nKA)W(NP>hN5UNO9Of+SJ(TO7hCzAYGk6S} z+6^W~Rxb3_tGAy&dz$p`O~ZeGkV=vc#^-KW=;^ma7n+(R!G z81I+})o0Q!Fmm9*+*kVtyFUxyTtdq@_z9_Lv$X|l10YKrCYTj(!VVYHQzkc(LL=xO zTc)5&d<1%9`Stt)jQsX{c`Y*^fS)v~@DBV476F6g`b%o6f0KTTd*);CEUUwz76aQK z#qJI{rOEA0$9Sw6Y9GImtL>j6I0W_{z#MY0GCKwy3pQxPG>pxw2h$gjN`lmI;mqYT zN`5W|M`92r&e0AInsjBNbLCAT{A=k;Z^=Kxf04~FA|iqpcIWy>dFyS=&xD5`X1H&Y z6Wgd397Cc{19uIN&j00sBJD~CUqSreCUT;R>8J!^u{z1qAyR~?iKHTJ z`Wn}cR>e&7L=>}mEK4i`9e*GrC52`X1F@hEZnZ2dEGF+&o&+m0VoRKLqy09)_P8pP1N;D-oUxPKO-yocLk^BlCPVcgo1| z{wXEwQL@dD8j4k1PtshO9lQzcQe0dt=(HkHaQbH(j*;+H%|gEnRcC^I|kBu6=u=muQhLnW78kN z;}8=pW(X9P3>@pr2pi~RBcm(!Uf5yTYPCLNjK_=r0d+Ib$s65Bev1lLN9eUrrL1I{ zv;_P`EH`KwW#~9)s@U(z_}XvuG5SX#2|>O1$YW(90OB*sL0womoFjA9z_xneo56-8 z&Z7(`jtyPqbv^PABq8HkFbEi#v9#EvAKc@{{sTzCfUjZ0hKzYTf@%A?R<7dNN~wXP zLCcn1BcjOCpdl3pTt=t+3@$9^V%SaU0$&LD!Z?Lm_7*N?tOIe_lKBmL%&0x$L`iAG zY2B{waITc1pW>9$3nQxhj3CgKAa5D9~z zX-CaVTUFS}IH(Q-C$xfNKvTIV0OeyCMG*fi$%Ck0SxZOXYb*? z^k*@U6OL!i+}zx-T9{X3=b-PzzQ<|Itgm_WqP5}6z>DRNf@)2j+C<6L9v5tAoR~`9 zHt143BU=H2lE?m12URgl3!1BTRVCr^F1D5c1G22Bp*RSPNA}yIDj+1@N~~G{tWWUQ1p>NZJrgGXT0` zsrZF&Wf`ulqj)7OY=UAvst|U9PIVM@6!}bV0b6ql-X$6wrzT*^Uh#(McWbGUdMWZEQ-3&NYAB4wYw&(NOzn{98R zMUzv2NX!*TLVV2HlydjT5vYYs!Ps3S$H(S@5e0rt1oeRe?Ga#StX)t!h0jyWH+$*( zscZe?tI%b*?JJODpt|LfMO5%|HD*Rlwq;wmdNEzZoAur$b^YEAnH>h=(3cg~>)?g^J6!Y>kC1Pu+VI-7YgjP|NDLw&1Y8NmZF% zmzQgj51b57lPJa-SnJODPfZz-kNsM(6eT=9%y5bfO( zmX++>vb3-z+6~iA0AA9mE@@U9y~hM72fw&eFf^ok=g=~KluboT3JdLE4;Jenvj;m# z6>(U|SfdXkoz`0cQu=tSFT4j#4z59tN&9~=$h+!LZ1f*XibGh=MnYI+&IrjjP zDIeQN3?ZR)f?Yd;3hXxuHRyf93?xKg*+>dfdR_@h zg9H$)GKP#I#=QJ0DZ-W=Pba*x`#FV1TkZ&@jZ+kos(gIta6Hf8$DvhLSBFb#5z_*# zHOjP#W&n|!@S+r=34Xx%Akt*&xeumzrlVp)F;d%0X zvI$2p)$@IR<|V_PxFPN_42pvcz%Dg}Z(!2b?CH|Ay8>Eh-1RhXI(f9mViQBGcG1c~6yE zw~pU?lDtJ8b^I{oa{flX}5YhBxmgYq~^WQ zE@A6yFE4Y)Q$a5+gT6ONXc}r13>PIOBSY@Hm#3u=Fx)XW@Z!EWYeqvAC&r&X1rMDLaUh*_b1h5ba|RcvJv_{f3epP8mQ|(&zsJM%j2W4mag`c( z_w?L5osST-y6vwBAG48Ji`HVfW^9~Edbia=@A7L_X2ww(E@}rK&0_rg`%UWQOwZu* zwLOO%o4!n&&2ML}DfhLER(n@JC2yP85y=|s7d)6^JW@T)$S(DEF{_i|+)(9aK(?$7 zcT$fQrWdlj#O??_H*ogVeb(o?Bt)Nb;gPDvwRsugkeQLO%cOtIr_7swc1G9kbSdBs z9BD8oeuo&3`MhR(HYV?z_I_{uvjJ>2!=(Mwdxbgq2IQT7Q?7DY*ZlC{7v2#uks3FP zZ+n&JM@B!$dF?RSILg|75qHuuJfmQf-u|bzP1^>B6<;mSkFe6WxN)_8zHAQV+6#P6 zCaL(Gc(it?@=ttUV_*L~@#u$h<-MGe@IV*s*V7*)C9UmuKhZ8_>55ZIE_`ohZrl6{ z&@gw+vR3aE+?~fJtNW_QXLX9OVs=B!_pg=j3nHPE|KY1$#Z$7>BrKOJ3oJnhSQRWAPN%Y2h}{w3XZC-&qCG zuWP3Nu4$v$v*EqP%L3hoZBebtbAj8bwduUU-(Lybt}xQ2a_C8y@(zsWY5^SxXY*@K z&73-(Ks3~+gdHtodxonRWQ(Zd0d0(1W+)vbZg+6}KSktg4j*2M9~m$Bw*jXcK={?w zeXRZarn2_{AFA=132B6j2!Bwuq43zhfB$}>ek~55AKEi&Xy_#f+s*Qhr1=V)IPkla zmGH@GOe3l+US;(QxkY>MD`8CmF7eS9H2wg3Q>WH`7^5g0Dw;WnB(-GI%&?(DcMeIVJp+RA$d8z$SdT_4&dJ!w z2-vs2Y;EQX9}j10HFW5LN0z6V{?pD%%*#KM{aYqn88MNP7I!kkrVG@ItvjAyu)Gp4 zdZCW2(KLRUIrcng83*L-+my^-gOa^hXK2N@mGpI*Def{q6`91VRX@FNXrwLt{`{CH z2O)5T!~%eA&kij9bvA75mrHIMzYP~J9-#HA?eA+ZS6h^cwg9_Pz?V_=8hG1gW|}~x z4-XILLx^uEKp*9e5YuUm?f1XwhV%TJ8D-8xj0>9TIcF|n8_2lOTs>d8Y5mrXCpGw0 zq^=tJFbiUtw|S$Z8fA54E(-x~SKdNT1#2@ScI?>Eyz<(sFp%VUYvVByhcgY1 z#NAdmUyzX*QKPQ4Hl#43ykx$@+&_R&jcXr>AY(O{X&4&Bt!*)PLQu<-yJ|Lf-nZG` zxk2wJ1`-07aSjSsSk!woaRSFurOIRfZ#CzC&>IC?vqkN(E0OA@c3o; zB+w@yEgT?vH!y0UfYSExf)0d|3^+TPz6&IymzI_?%Qhu_0YrT0WAU8dmS26 z0-~7_|Nhmh^}uUz;(pI;=^Y(8JWeU|Q_@GmoPg0F8Nmz*NSzY2p9)UoK*A-5d1(V; zOQ!D~-YA(@G8vHh1s%j8-JWdnFyU?ZtcY)LZ|=nj%}Aa)hdEM10f;zZtOVgCByKqf zrQ8HsBQGDHCtL=Y#5-6+v2k(Gy@U}BbR~!c1EN{*Nub{Efquzvly9SK*j;>)Dh5wF z+B2KtjA24{VCx3_7LZN!E4cD;8NjNcm*KiuQRjvgMG&|lcN z0ftU8*nr9r>@yi036y66#3}AP;O3c>m7p_kAzF&_JcuI}_)oZ8UK!c&DY3*T{V%Im zMa!-sM=iAsCEsZoRAY_vB2GYiKAs?PBItyxFk;B!Zb(Jszz*q5_ zW+S6W?8=?w(+I7Gx>;@%L|72I#`J2)j*vLi#|E=y{CHEos0XyHmd#A&+ifVPK5RuHyiI8G^wWqxg@HFO>@`m%Ugf|D( zbwZ0VvC#go0yPI96MhXoqI5Eo0R<)S{=)h5r&wqZc?J=Tc+E&-K=k)k6y5^Z0hm$* zv)`EUfZ%al0sf`F6W|j=jXt3cBlBc*i0^IlS-<)3l z(^ATtuU(Q^YX7TC`qZIKP1BQ=E4YTj!(JX$gMe%KR|4(+5xp+OKAWn{Jg9uBy@XNA z+>T0!KK1Kq>z|qTm`;c&O_)%<@8tVrLW@8E6huUhteq0(0RDzSg7tw2;;30ygnE$6B>)&Y zzmDRcpUW^9mP_ENQ{&VZE7oIU5eh7mIti(xpW`KkuHJRR4wmBGoh`cq5U8Mv1dr!< z>jwEWgbRy&U>_PrL=*fZiJ%wcgJB?#S3;6$ID8NW2yR4EHvx*9 z=?(m=&yEZXE)=W{%FxqKOAbC-F6lAi3=9oyAWC4_FQHLMYc33RdTbU?3ACX( zgye}u@gNt@5EXhbF(wr?gq!xy_XnYGE*pI8=V zOH(L)eJuz^hCY)ZE^4)zJf%{lz}$eJpz8WfRs3lPGW7c z$##LA$lQ2-)9(oIPP$h1mG^|4P3V=1*hn*j;TyZbT%e=4!ZeLXCQN1ci5n`id(}lP zO=4v}YP^a5Df^Ee-T7$wJtia~j^d>Fh6_JlnLEhBYk!@O_3f3}J_H4OakZtj7ei{; zVP9d1!+?|ZB4ZA*!Ix(ymekz5D%kC}O71lgHR)@})ASsYPrM@8Z!d=&U6a_M4KB9a(qHRv-n?2DwPi zXt_w_Mw5YTID+4azzey>6Q7YvOz3&sA_ctztbg;JNSN6g2VJQ#_Z?M$S>?%A?3v||OBrt17&1e=j zqTv=*8G}ymb^p;L4|e0Lrp(b;A6H0JVs;?{2sRJj#|W(Hi$Rqcckh8Yj@qq21#$x5 z!bVO?WG50f&UG^e?3L6Df-D&o6B(Uzt}SZ}S3+s)Ku%9k@uORwrLNlG;4oRS9>0Ks zUJ`j~*R5YGCZLF9%;u}KS+%{G)iK&bIS4lXDkI|?&DvnZcQ@=l-BZ#Z-Bs&m@zp2G zMvWLjE-`cqV9?z&!=d92w|;#Gj1)K3{nYP=K%`4~C9_}59-_Q=&6^uyyAJg<_?dgg zIRpE)islv;N-8SqT0umID*k%$z2@qM?02*0{mhNe-mt=;m-#bi)x(N)x++d>_{{mp zxqdlkMjP7MT-DIr6?#f_hN8VfTKzh$E^cWxPI15I_gQsT^*CEGZSXONFJD^3L}`y# zT4--NCM5q+X^&&0ERsf6ydITrn>?~2qZor}L7sux1Swn*){=>h1m72jr>#uAl-_LA zfn8^0iFI}^8ibEB4)Q=Sk{3ovQwxftD6N>KLxTbcEwBlYSTLwV3Zk*=F)fFxfPocS znBAmuI5~Y|E+uBo$UU!fz|w5O-#K3vl2#aU!oaRf;U9`rrq3sePCVG%1kVUqGV;sO zRFL&#deBO_Zo2SG!K0bmb^+|Oc@wAb!{$%{E87CN$?~S9k0Eo*2WA&xz@XU-|DAPS zW7y2uhk7)kbfuHuZ;r5j-ShCi)PAs2&zFq?{U=3-bHZ|5;pfknXV#9c^m)0U7n4Ye zOq+GF2Jv?enRIH~{ zPxW4M%B!vwU%$?tQX7J8I$B0@j;73Rjfz%c+`D%tv&rH4fYca3dZWlK9o3zUm2b+`IiQTr42! zrG-PN0fdju(|uqanfv+kOiN2Oit95}=MO_KolCo}dEYvcqh<4=keWwMh%~6&RHu1q zWyf5-pT3|0G@7AnvwSE-!aL(l&nrNsC5064r-+T=BB#As^%zIyX$A+!U9hp*%gX{u zg$Xx5REOgN>c*x2QycoHiGLmx27DL z`@{WR`3ON}#zg)gj{?#&=ef%1C2)!5)2Ba1?!7w+5fy}*TncT`FU*=n>w0(DRXP9< zN6Wb7&gfrlICRiVk@S(eXU;xpiL{hd+Pd(ra2P*!-3j zx4-^4)Wd^H#6M-F(6E?_Ab{wa5UTuRII?ZD_+Z-O@i36{f<6Le$|BAb?j`#p3 zjJUY!+%IZk4}M*liB0cLc959V6J|UU4jK$|B3a;_(KX>bpOxbHWpZs(v&_rP+jk6BSU_mO@-dUnVhaw?WLeas{7e*0dFw|1$^%YQg zAmyE8_Ykst?$nSCV@S%FLy0cXxN!($D5PsjxW577HQYesk&GEqP2y zJvm>4YV@W}Tgvp7t%np;>heJN;+F9Pp=vR&X@~HFjf9OD{k{a-*|5y8@0hT=t%i_8 z*(9ZaihcB`5v4Yxq@xs!lzt+3l6f%AoWv!eP6+OQ$aCMmDM2qqyljhKM=5F$>1E;Z zpofIn>E|hdsB|?}ctxY;bzz^L9MH z`MHPcv4KnLNOUxtvIS-S=<-))GwLV?8zyjPen51W6$O;no!=p32P*w-jg(@KxT`k2 zck<9stBh;AXlxukF8=tc8-6uw;Ceu9eT$vlHLU{dNIb{_gcwgmZ!h0878+gKPLdU1 zz#_C}2#9JjaNcw5;mmit&94j# z3;SAHdjHKEQ;iURe}AoEkFY&Fd>9QjoPnb-3K>k(8x>RoK?PjD-hP@Fbw~%AZwo)i z9ZY*K{@TELVdFe+)su9hPKosJv1>F@v`uQNS@}O)02ZV2-W>p7d~o@35qM1q(M3h& zl4t+EyT%h?#*WR%6F&**o{>vYCkC0rZ5E9gGdRAH^YK2?U9cF65{eaoqPImwPdHLJ zg7N6TP<-yHYbO;IF+Gv}|IP`fp5Q#k2ANGh=xJeS*cOkWww!#zR;^V=YFJ$%YKXhnoSeFtS z$K2Du{<~0hdZr0b+ab8nD1#AkKj&utq^(Duh^xl=vY@p8*V&tZ^_;iw-(}0t*eMjD zv5YN5DwJJAk$p=k`_iV8ELkgCmS#jGi9(8O5fxIRX(0(oDzr&NDs9i}%FOR~KlgDw z&vX1A$9>=P`!)G4pU?YqE$4Nf=T#K;a?Q0BPsaG}NgM9-jJV5+6!cRwcf^tEa_O_U zc|W<;j-8m0_M0927w2Lz8`hv3!7z~D%Ff<~ewXqZB7u*NP3ZG=tPtXnAc?`|3;mE; zzsY_+xu`$G0wcxZ@?@l~%zQ{7r3wbv|jzLP$t<a|gM<1_4R>bw!5{pLP*sbTt8>!By8b|(2fe)~($YOsSVF@F zd^+q_)yuB24CT4W*VblyUq3P^ngS96nJ2SZosPRm$E>{jiveP-f%OmoYeAdPKzZyi ztqoonY6#du02db;R%*S2GO7<|kzh;hC+iOm@wI zVeqbwCwfF_e2?f!$6=0juaH;UnW5RBRd&mJj~*GB_4>T=sk3*l?C6OBPZsJ7ZACR| zYF4F5tJL(qO+{wE3x@JHi4{NegG@eG& zcEL)jCt>j6Irpo%x8`m!0rK`P4^EprZ(c_MiExOjNYg*mY5#=HN7-vpSi-=L^!-6+ zLrQX*UtgocKh$<}j}cMT?sa`Gu>4zd?Un>y2zj56 ztUYh%`uNJ<3=3Vqm!tgN-qf&>!t2aT32_Wg0VC)Huz-qX&lFI{8&d_g94iwN((2d{ zA{FG|JxI9$03Pm&QBq&@AS;rt{~s;AIKBAET=j&Y)(4p8D-Z zLOAYJvTRaN9Y#U3GLmWZO{}dyl?<+ME=!wJ7hqE7d*c!&2#eNlsbCUQn|nvxw~Uk4 zMlVr-8ylF>!VnH>)m|l*6GJxNlA6AMLJwd!TnE|e1356K`OH?0vVYGRz0+VUF_lqN~(Q;(?Bb$?f;r#+V0hjwFw|>)PIdM z0LG=1xi=B94N@y!aT`dHIL=V$fh(}UB0s7#+3T^i&M-EHT94=>)Cf z@oxF>K-WBUfdpz8wzlwx<}%Wulp#Iir9*X$;>036Lw;2@wE{jf0AxTTjA0;Z8r-J@ zcsLA+d=XKglB<_cCh^QLXdni{o|#5Tz!w%dD)9{{kXg)%tf-N6XtIyh*VmXp4tgLu zKx4gjvOpHx5qY{`aeO3pkAg$|I`4?coP$h!En&YCoiTRMW%R)}5Vkk69r*h@(pD|y z#R#nMrAKqqAVN&L)T|B@8(6NUu;QSs+OA(eM}IPqd^U|1*%VauVCPYWE$>=~dtvwKRW3H4{Nds8u!Wp3vU`S)kEC>o|jlcnasW=igH#m;t{ojvR2l%Q{=vk z+N{rtD+WN4HI4{GD)2g%Az>aCUm6T93eVTU&cmDir@(H3bgxlvTT#*4x{rt%Y_H-@18Ii?0nV9OY~ZUwp3&*Arg|} z_OK=_CK>uO9i?vuQXwD!2&Litwqg0>_NdDxhsR3V|y4sI;Fq>&=Sid|GTyaBTzd1`nl;l^j2nZiwpLD4MW zJo;QJe_3h1~9Fhw0uwa(V4D<4umxJN8(M$^AEq(JLj>r{8fK)?!PJc$#JlN^u zTrLwQg83WAL$tkOOG6w5XS2h8jHm%idAfcR7=Nc|^9X6BPzE9Ltax&|G5F%$1F21T z^2Z`OhRP?MB41Vfm+%UN%`D>rvLpFHMCcG(|M4F{hEqw);xi>!hIw=>T}HYb#5xV} zM+KlG3T&{wL3oU@1`0c~p|lW~9e6TX6AKaEjAD=0stI$B`PWyS-SV7<_}SJEJZ!?> zgjmPJXF?q#l+iwYjEWom_2-|qz}rK7t{5O^EI0CZ%XiA=(j_{-`rnz z^$@9?JS+@A3KsM~sg==O*oUWAC>+Skn`32?tM3 zgv3qqfY=*!B{@Xsej@k^=H|(Cf@m3M>kr~I=Yi+TM3+aw@xlXkjE=|b850M2 zyh-+wvT>6h4XCl_v=)Vn<2bAhFGJ0#{gECG3u6i?A5<)Wyu?!`7Mg%;u{{oqxKHk7 zY##u9gsO{i5qNWV@-C^l=L}!!pJ(S+B9s+4keR1!g=a7pA0IDxDE%ytF_Ki>o}=a4yW7%@=Y0M4?F>87#Xc4Gh=@Tm zt)oLjXfwnv0{mO11TvlDUZY<<$`_>sq&?>`lbc2QL|{Cgg>OtlL5XF4tf6trNPpkn zz2bh$P>c*Fd{?gYELZ+-SNr+6s5A6E?;FIc2~UT?))-_IX%=CJcnRszD=V`uq zh(?ABsE8SCl-(C{2(WG-r-Cz$h-4xI2XM*La6Cq^e3M~W*^wDrXd)(4`G&4mqNWse zDrW`{Vo_W2w?A+#@%}j}G$NFBGP|+27jFo{8aQJC&W6khBq^~3wE?II2?U75vhdk? zppBfmmP?Bq_och8?lEw9!h^1^uDEbeJR*s-&vcl&f5KR5?v)ug z`pX3nu)9|;CBBfHLE;oKDi^kp#J{M`8y&l@r*7uO6{SVIO5=vm;!@y9#8$7uZKlc# zr3U`WO*u=8K|Mar%*>c7DecgHLD*6|ZQisgKmAfy0u3Z|amS>rL~%05%j5^~QceW{ zBaoS`%o~i_aLFwZ{bH`Rj@kQHtWJX+=OCxVYOhZhrbT6sXwpfhiCe0JMzBS+^p;WH9Mg7s4*7S%_it{h z983V56+IT2vb;VYR{l)=dHV}y&6z_D z@#aj->S4#Fbf)=XQL*+*pp?zQ!;upv?h1TtNNOG!)6Q0Z6gIb?4B+HGFd4k_XqRW)uJZjGuFdU- za`gO$+b;)Y-i*YrhN_hBmRnG8{zxn>0k9!UTV2*5B9jcDpR-}(M)3lmoc4O+AD0~Y zLv375Y5TxHG9u{1R6(r10{bv|)oTB`K^|>KL1f*miB& z+!w|WZgLzmP0&%&h~uXXL@_qa0(?lZ21Nnn7>uzIkDUy6d1%BtOk^<7go{Eyyz%^L zj=_x=cU#E46cw(sJAoj9Z31<`_@qj{{u&wvEQx*ze1Lu(64qwwo+k*=ZZ~B1$9s5{ z|J=U7**i<(sRp)xPoW`5H!>x0G8R4_Zl?t73BhSkQ&LVj?d#WJve)^UI&Ia}jTyV} zDil9vIuTS6+qkkIpAdPOhOdjMDXw={6%Ql|R-RfZ@+mK*_W(r?P7Rb^hrmIDOP_#I zKI)Yo(l*guu6XL-jFZH(K+8;TIF9;UxSdcODT*Ou8XFpJjfj%9>=1Z6dn&X2@a397 z+}CN)rOc(mj+`zi9wzdR`rNFL0e-y&G1Sw#)9 zp-_QnEXyjypP8$wl!-JxfB zoGONiRm+jzTFL5nNi9@(q*YG&<1dd9e~NvWy+yL~ z7Q5SA^3}st*9Tj_9xhXni=9_a$-Af2bqNU(aw`K1ig79`@v@bPDo7)YO(KVR`AetU z>cmg9=ZRQ3!~=&W;nn^(ijb9*>BQ|I(yO>YGFn}gagUH&M(D^uw3XMFxsf?`itI=WbrBe}}0)Y|{ z+l`kU=fdOVl&AWSRgz}J(9qE9(2-#M@BIFFQvv^oSh>4Y7Trxvz51wqYFwX@bOg(I z8bqoN2at+U&>&G6GWyrxrNz^j`zVGObd=8wEqDc5u%VA)u2<<&F5?VdnzMHxD8p&b zWkXjnTZQa9qUz&SdKj6&JXx{kN_6L9&fd|4eieVcllb*<(a8H<_a49bxPx_Fb ze=c;F3*0wR;IIkfcMcu0HEk;%}sqp>N*3rE$&SMp)p)4HriILisl0 z6MvI(QurR=io{9ExwLC^BT@y!(vr;%+zlQ9pA%N0)&>Y^EOEJ@`JRpq>h$SP9m`Ibz7Dtoe-yK{w4a)-~gpLHq=xd!SSTXCza7wpYGj^`K@rKb>28P$l^%J<5z;)@Nw&g+Q6ef-1@{qMC9oYUD|MJ{cl-VK!U%;6gG#t- zq;0VU!Hpo1u`)Zqax?kR(L`2cA!&1z%;numn-=KEC zt|!3&XkW~5YiB;(2gJ9QgY+Nc!p?uZE_@HX^untG@z zw%(a#>|R&?`W{ALr)&3(_SW$1%uukd=b)_rzr#L0O#OfUcQ80kq5IDt@xT8EKV_g= zH0iKIf?sg>?PH*a;A=_H;kSIxOStkk09*`b#r<^e=y|tLygSohkZ#-W|Mz1n#@loQ zy`w(_L&2dy1l%av<^O5k+=_mM8^g%Q8D%u15CvK%1|uO&lsTlbN{2#QznP&R2Jis3 zq+Y@PPr^U0N{2N^Rev7KHukL(diWfaFZ-v}z1V+!0h(^Nt#UZs%-S4xda<+moZCB2 zG6erM2AkQ|b>c`eBhcA0Kw{84=zyR^()Cwkt3%aO+pRDMW8m&Rdw$SS-_`o(Xmy-I zX^=RmLumLBj+zyd4LSW8y2FQy{cpbnks(S_1!MnN`DFf@dSs~({DhMLn_$8OSn$rN zcgQ#p%jbkHRMa33GmI#61mOYSg;PL?Cel-5OfwIk+fRfk^xQuw0s`_W?#i^zBTiEG zQzAn-i(b500fA!B=GY--vXLIs`lcG?>pieD_*INnsM0%3OZW_W+t z3k!5($w)rFbwx*L;>&pQKoU#=>Hvs%>jzm`UFRJUTXE4pLQj!7F9MR4wAcSI~=31&B!&cnM?gwP3p(AKX(v_+d-^5N9v~r*GpWFL zw_rR(14}hY9nS9rmkd=^zP9G&VbCq?$vxo6Qb)GE2ak)dbiXT(0hI%!UxQbD2R^~YXJ5~FaoiK@+ym87)lk`gjdl!5jESh9R z$ELso&aAuoKtf>JsJ*akWu~m}^igI~oDjet z7@4Od;N;v4SkNd-tdp4AO*(w$LqXy4vlK*BhZRU67-r^ypwpFgW?YJAWK}Yn&T>mudc*M%QezPSTqQt1XbNMpGEJ zC{XA#OQ((B-7kT}4!`{Dhf734(Ayc2F&zxYkB?RNHb1N>vK1_rL=y2i*Y~QlPZ}SY z=}CDCm!eghHe;w0i3{SFc3SbD6S$40A@*R;nx5F$e?PmE2jqB--j|}5RC7)4{tAXWYQ%2ZV1j|3^ka=c^pD9wnl8lP>Lxyb!0?*H>n)bTRlVXmyrrKv`#lStsM_V3xrUc&60p_dWM9Dw)LK5lXMA zN=BBo`p=kOy{MR#k6w=?z_~=$PF30Zy0GUT^=0E~!!2j?KTX&hZR4bLZgqI&dC&6w zH*R@-+w%L=^r*U5Yi)u?>}OspdIvoGdkKr0W<|a@zOp^{e{(AOr#!02(tN(PY4mRV z)R`JR1VQREa9}Si*hS<-$7QNpAA*IPwbT5_gaCh_QsXWwdQZ^%H*9oo8r`Y2?axo# z)bdx4`p22S#NYV&E0W89zR3UCPd(}t4gXdHbzYiASg~msJxz8gHo3uoZfGYmpw09^ zzvJQh)_0?)AKQ``(dOq{Dtg#vz!gCrN!s>*RM)vvr)TLOovQk$;!5})hq-R(Ab>e8 zU3zF4rXVwAnW=zjTOW&~%tMr?E!3^z7G-cHRH18KD%CE<`$TYUG4tb$O5X)BJ-W~< zne78$2o_}GXy?l!U+%J{VlfTo_<(<6t75#Xd#1JcEW$GmgK@rO-fZ&)VU~>v69VrO z0geaq5KwY5CrtwK}&ewVP$w zT)_DU;P%H8-A?!BCxG(yF>lYosD<|jb6-pAv)gD~Sk7L!u!lmPs*iS=s0nldp9f6x z`U#rey9WYB0hK9G6^o6j<}b$+Cy-~a^b5Y!P`C?733A`Q-I{4VCxOV_v2BeOT*L^|(dTCO_Pds;A+Yu&;j1Lii8XbNX5zQD4G>o$j zE(2f-@bBd{!>eYUqwTEe)3;;0hMOcHS#WUhaMgbgeQD8*cDtaRUEN&eBsd*4V4uEy zb4jZ>qYATF(@1Rhq}*a&k{V_;5y9+T4w(=po?WBpkr_Y9R_5Ud5(MI+;j84UQL3C` zyiSOz96~>fL4jkJ`Ajo%Q8GzPTqO@_?uMN% zf>m@4$8g7lWlX6}Qes3A0HQ|F!;4@)H>k4m3pHIEX!Br+!Uq6e!@|dL9B;cvK07t7 z7(rjLhqWg}D4H58G9wLwbjVyA_ke&N6lo*ss=pF~ zYXYmpSyi&y`^W9M;e=Yz5{r_9yip1+GaUmZ0eo23lk)0#xm4X5E}t-EY7#~%Ot3* zHD-s;6iv`Xqg}~OV9+8rfIvj3(?DC1>>fy5mJ4MAvUb?A#7;7cVIVC0K8}}ER~Q;!v5ajd z#0Pqi-hKKA%@+kAM4`tZhp(47u#I!ryn|gjbclnbLW_?NsxFVY9hZ*5M*{gGp4uHb z@=d+9MFedT7IR;(LJI5RlHcv`WnYbhPP|+*jP-%rHI0Oz2vPPRVo_l&Qj5tbpNx!b z0m8IwMFjemT23sAFxN=AwQe~}99Z>WeI-knAl!YJ%-O!{-*jU($$-i3pD_PgaZm$$ zC7v7res~FsvUvnH!2%U~G7%LmKO4|{kKU?Ny&oH=cjmz1YP|x45Msr`g%?d4dui?_ zp+boi%nj1&OqEB+6F(F^y^>LkV}jz_k`h6^Z{D2i+oX(O#c2GeDuL~gEoFb`XMV`v zM%CmGDHLWqp^86*Dpr0tB@~##Y6ljFQ?i58$TtSKW{6ktBCLl@3~b&k4B5d<170K! z!NUkf$l&)g_ju#5Rw4;^o(kZ)GSx3!szI#jplFbf%DEP~89tqIyETpanMGjMqCyM7 z(0R>t8&)EtLy(NhfgT5yh0F6Be#>hAPX!!q_X*dO7P$n0I%sup1}Zt6r(Qx~fDqWaj#nqXg-W z9wH~_w5P`%KwJ=2Vd}npX!-X>f z%F`k|@0{+vhAklQoj&7l+PYo4oqm4iUg^XLV@A)igICnryeN0$+YKAz&Z?^Mcv%SX z0DL=u_IJbA4~iCHbJ1fm6DHmB>=)*Xs+1DDu~5hWTa7<8bJFKa!fDIKPQr@N4!d(+ ze^(b5y#ph^tMUvpyWh^OC&k;m$}TT2UrrAo5CCzE()2#w70(Wxg()RUcmkfFtQ-ia zDOAs5u}BbxnhG(}zsZu%xlIMq7MK~>oYs-$Vy6Z;{BKtlY;R`=Ute*&sj7~(8YKd< zE*QQP1cja4=AH zS@HrhY{a#JqP~>*84!az#w*fCbB@KS(L(DpCz85)1DFBG8pkL2JzAY<6MqMJ_GvVB ze`O1%SblZYz39JbT+S8ggE65stpyOn~#2|D$wMX4Om3sl_P?4 zqLtWzLp-8LFm1OBK`Z4(KDa;6{HlX+-7N{QGRI))t=yrz2YSrizc-6%i!uCU9>}FI z#RNqLSswJGUV^aQR_XtS85i}~SJw0JRD&ipb51vkUD!3O#(ZMLmsPG-@CW`ZT6EiG zzG?2vegG47I#DHs(Veq`dN*TuCwvq#@ep$GP~X*AsTEPd`jtBKXV?ea$@)DyJusu< zmd+mmU#D z3S`AKygLZGB;mqc=>}d468Dg(#-5$qu(a#!{4`hds#n+5)8evhzSVVJyS^;T;IHpf zi$D53t_sn6KF4N#aPplW*N>+qr1_ZwE2A$-qUdE50;1EGot|u;%gXqapJmLqd=1^=!KRbKR@kCHdzb zKd8$s(f2y`Xvx#I(w|GmS-+gDy>Tquetj2Q6gaYVjKyTTUM?{RXHxo25RL zbw0#bLHpow=~DG=K!`b)oga{Dx==557Yf+`@4aBjvhfKfPMK}}Cscel>FM+56F_7D zaTqgShTaT0u|@AZ2ffOeuC;~~aiCzr@6}|{T5wvY-*at;M~s-D(aHjHtEfm}9*Zm; z2<+y^D+#bbKj=hPCXP-{whp&aZ6frUIcARSh01bodt)e-1EMM{m1Evg!OEgRS^l}u zF19_CRx!Hy~UD({rKF^1pSf za)G)Pt)Lht$<+Z@MC|L4wklRjx!;ko28&X)Zxvn$7TTuRo(NKdsA6wyn@*p%-2bK5 zW%j>GEamG5ov`0?AG=)-k4?*0De5lN8P;zfN=`-WwmBJK4U*A%9}=Y zbz8hMZn4@FfDKrnBZzz=!zQ3%F%$hnw@Cv&8&5%zH`XkaI+1p{_{wX*DuGGGmadNI&-`B|Dq>$G)jMpK z_01Ypxt}nv`;jj8GS{wO58G5}KcY)ZJ`Z;HS0Of!JsGfAb;OVS0BIV)=M-sfWDnG- zQ(M8?znFWGzeF!Ae`sly%4f|nf>{>S$l6P!11dAjP&u9MN* z&h4zbFp84H*|}o$L))W)Mi4M5{A2{cSobM}Latgq%PRQd;#SI6kWC{ieaNuT#`h+? zhrPdp@kPqD+t@pcXD94x5{US5kRs}gj&~5b`*2^Ag#%>ioUDzL<#05qNd|SBT*?ZW zf-pJ{<0wWWG>A_t{hNm@F&Y z{u|(J_wEL&{}s;~x6+*wWt?@_bEsZaF&hi{(@bOg!`#L2N*e9Bm*T3F`?b;;uX;X| zlpi!->Q}7&lFNOcfBamz$wf>4#%YDpbv%CK2ncSAFOxsTBjvj7$J?hjELhMP2u+iL zFW;Zjq5oG#`1l8_uG=$fo?&j@^%cBiy}#J!0ShgwB+sq0b&BNW>94p&mx07TfeEG<*u&oHg$fy;ei12_!n>dslE?;x@sAu|u8Bl; zA#K%r z8hKfmiy+nueynuavcsETB)jLB738w~ddt=u(=FRgYdY431Oky1oms(dwcSO z34|pT^G$=`CcF(iZrz;~O3Yd>&Mq1~$F@HAk~QzEx{YQpF zo09rK+ZZYq&#fROwAZatwSmR&y|>SHx?T2G(&;$GcR^VG@KlbbsbeJqt+ZoDLs@+b zz1S_ih~=8w@$`F@k+Ff)C-5IaaFM;>l5qtEDoBb7__Hpg@%c@ z+vXINN<7EW3cy)Zb9`pXJ2%~GUQ;+n=nS$C0$*xss}-wPTfx{SdWsbmsr;e(dNu3t z5th-Gt$*2P|8alzB z^hWTH@~jezGPMg^x>z5=1hc{$uUqW?!MHgr?ivAvRv*JJoFZR$)b@rL{8M}glz+8 zS)(jQy=QJ`N0nepAA?ci%L3r%8?r)$t#dTbMnat1X09J#v34d+h zTw)(&9UizZxO#k*|7K*>9@#q}!h@R4mTJ@M&p*$&_m)ePrQd&?^HIuN3J_bc=W<9x3MnJac?jhcen8{%jBb?h*0sD7$blD%9-Rv&*!g zSj%5(!ZBnN&s0hnY}G}}a^PVM6YPZjI&b89F+Qp@I@{^lzfWd=tOU3?JYb;SHy4KP zII`BphE$&GbemHr4&6v;sl8-Dz4R0QrO+*)z_Trl3pC=LeYrvl_Z?6!7%mdo7;t6V z-x5qiRJ|%HLs(&|9MiO>mwadY;pdt^U!3Eh$Ik1Rysxd9VNpHb?x&*MMEGgWIlFt! zWgCcWP<%RhAcvtpyG8a3B`-KMV$a2k7gJ7sfevPU>wO2-JjrAJh+bbWZKV&7*dXyh zfs27oG!b`_6>H?0x`96Cd~tS0WF&NYz*Z$h^#o|*IJ2cwAtA;sO(keXt$$AVs}14y znPl#X9QbLGpWii~_5OJ_8oy^pU!b(kb|~RW`ny+}NS4Sgui`%4U3Rr5$Hn`j zfqqdGbcPXe-033Hf7_r-%^EdO^vQUwoEY6Y$!G5|pMc|XE4pVrrW&!moyp1JhPc`( zzMB@)5U9Q|t?^{JAmg@ZHG?d}A9~LEKg~2sdlco5t;jO*t{Q6`9^7a1KMz<_)}W8v zeouq8Mb=0mXDS7=a1BKeUmhHnoJ=~o}f8hEI^ z`z_Kcw$#&)waD>&t}!9))cqEO%w}iOuG9i90SoDlM7Ff^`zxW`OffQb$Bntp5YEQ< zi~bfz_lA!@Z5*H!Y?I|zzSiiaYh$MvEwoNOS~XSscA~?;MSl|jBQ9EHWtG>wq>STl zg1(>a(1GK8$WJw7=N8qzmn4fP*3M#3Ec{L10Gl zGV}r5w%Uq^2I5gC4u3(ZgW%$hio>rF`BmjZgW7wbp(2QpngV+s1qRAP;N?$?bX)ux zqn|72TqSN0KY^+9%A@N>Lh0E@nu0OqOM|it)S0gECW|mglR}o3Ejuww1?3U zVmgcWgD^X*v6EWN^Cp`�MAG1R+FPN7p#PTL>6 zi(|@|^dl-0Mhe@?XGokECi$|fVazN~ZYnjR0sc}|15M*ge2)Xuz^#Fy`GEK&a4|WM z4M~F-0HhLs8DYtuJqZGYVpdbj5;auaQm4!gF56nwc;kXykVdqOy>R1f0YXz4_x$i>v3&9bk~6CX~bsp^bX` z!}jI_G*p#2F!y;Z>AxFFpTRYHkFALn4*zVlWQVw=@00Yp0C0SQvk02MOZ5r+qeYYH=qs;mS!~!p#cMA*alR zIv-*YPC)&{jDV*w8Pc?P`=IDXtjjsPt!B=u&Fed8pCwl#0vreaLyeb?*3(cyNMnef?j z9QuB5an$<1x{|7WXSIxnw3~@aC@AGh$#>7|BlK>pfA%CSGWTle^Yr`+NT5s3xz>Hn zD1ZIk{6UJgF~?Oru7$b5*jhjVsc};`eB791=9?Oo_cSak-7GIEPY@S-O&Ji;YB7~h zx%tBU@Ys+qN4&k~TpBRf;L46j!>%9iIj+ev80S!3>p1Y8SsHmyC1wa^{hXKS?wP1K@G+D&UFa?eKjl_-r|wsGTa>pK!~XoU`s zjdxAZQkFaXevErnk?QK~@~U~5VS-T?eA|F)0+`N-cX$0mJ?jdB{JKo5k5mF?->n@o zMSV?1RE7bfPd1XasQ5T-^cgGTgPRkIAsF+dcF}77+&}4wmNG!Fp_P@D_j}isS4YVk z$NR5Tj&I#vRar7RnOJieDw^A=t5W_CB74vo@67fKlUktbhTUJ6@r>?KD0 zTAa$ZCq(M^2q+@Y20xR*G;eGFxKGfEeezj7&NY5#`%9w+GFF6W{DnFMB-$yy6!3d7 zwu<6-YUQch#4p*M4-M}Q$C4rF&4sT?N5S(V19P(S)5wkMiPDNR`U10pvq%Xn8yY!g zEnNNvdN&zWxkQ|nY204*IU(++^!z3UH4f+^gm*MGnjXvb{Rt_ra&(#QX2ZF zL(~EUqA}f;X5ZfhldEuYH@W|U69W|zP0{3Jm$^uglF)JG;$l_l0tFohze@QIhItuu zr>C*c&c&*dqNP$I2*@&0k=hMc13PNFRXFb;^pu&6@9yq(GMFK+O84BwqPbY>@b#~rhy4gglcB1NrXJnb-P|wo zP;}ax?VvaIeWtYzLN?`)Rc{D~JGxxWJ+Wq3hT;(W#tpWm_;e$MQJm3FFlNVdgMta- zSBw_PoPfh_vsQZHz;YNhB}1o}$1}eEwVe`G#gFN7I;!uVr#X{-k^qH5GN(~;S8iZ< zuJ4}@bN#Phm)9oP(*2P|pFDj!28y|)aPkVo;U~;ASe^p7p+JbHTo_(_E%oNx?ahZ5 zUA(Hd|H%u3*Rn*7-$J|3pSsHFbNh+=5s4n`oY+_IE&JPVPhPwbK_}ryn4=U2yeB|r z_MbCM#1Hm?ma-7esL4roU8Kis*Dn8m4#x>kU@nt^)k;=AJ(1sa8+hk)1L^IlV0btV zfjw?v^Pfn2!MW++a;V2*EW>O8Wxqa~F|~DMBFSx1)57Lp3z0%n1xzP>)9 zNV=nBrtJxZX~DPN9j>RmFg)P85eh;F?v%S>@gKO<#@p&c!*6x;aqV$psLGI`d6(4_ zw2iUs8I!H3H+9}^8;gP$QLY}95v5f&Hfz>krc|(XaMh6^$^og#S?@M|&&n(MF4$zH zuCVax=A!&(bMQl#aT{SHuLN5eK*aQV|S=V0(OfV zci(1PhOLN~bSkmdGR8ftWI0)`QG;zUTl(G3>{7U;9;*lUX-?D6K8C+rKAm;mO3$1Z z5lG3rH*^&qaX@~hi;D6ncQ3uVN$Gk2iZ3+dP@31ST^rG{{>OVybvPKKrlseQmiSoP zSON*y1oS+D-ZXRb16VxK6$`F$DSh&?Wj*PzsjR5%rI*#zl*Qw*mW$Cy^DFzgdq5ZT z+oZB-bkUf}Fq6ZEjyV|=eF*6yPav?44L-M5zFc)H!NZRRKB5#57vD-A{FZuMO9fH1 zvg!eCd5VwrZtxQEq~kbF;UNHHlg5@$A?x(0JUmwVh^Yd-5e1R-c&O>R{dCkrvpbel zgo-ebPFXkvAn3VYoMn?Phy|qaQNlaYeK#Vp{vu`RT;HnJleh>JD|I~EdR`zv01eW6 zH;Ot%@}}e$!NtHxn#E|{%-PeIC!Ut1X^a-sw(gL@s9!-;#iA9QU6W)5FY0Gk`yLS6 z62}aIte}*v!?jZo`nd-IiS;vj8sq62JsaD z4w`ABRP8U7n+Q2F^oMq_oD6o1(I6F2it@sLzSE55VRKc7+gjw8?+7U)os3nq%KD-@ z%5UJes}FPU(GfBCu!99F9%0nj(pJ-HQZ?GsWx^yh#)1|En&=@8zE^)DZ@RhrhKOsK z7*KOGWS~P+U(-1}Ne&o~k6Lz=^|sM5TFxTL9Igfc;})?{*H=3DHa_EvSa=9|s($eV z+gGNfDmPYQrb?LLcUi+UWA^L`bfA!F2~Ulqvkoj)rD@`BLKV4RQr>Xqje4+{r*w?N zlpVKiT4@mnzTH$eD2Z0rXw_7TGoC}RK2(as+A$-qQp^mFcqLt{AU#=(a^F*zDqp|h zpgi}Vk;b8z`&#=<_I8mmrH9&iZ3V;n8`bXTKgKDJi<;Q;@iGsly1xt{Ya5`mI~H-RiUS3(`jJO})CVZbp*!yoJ|%j(SXTTk`FF>e|XR z!LLUDF{W8wS;y^hr{(#LKQyJkhPx4?a{8Z5+!yBb%?>=L=R>p>C2j8DH zrrHw;4L38bY0;$YFDknN?80cYZ2$NDVeUgBk}VFK4N_C_iwg}LscOYP^7Z3=b;(;NvucSIU z^y}kMF^>vPKFS((JlP=W_U^{xgX0}y?M*(}+U~r1;o{bS8G{|a{)60kuYfA#?`NF) z@yfoEy7@X&)|Du%Q*hO~x!!Y;hDDP>+cYdxQ%3eYwD*cqX>@RH?9ta=&N&I?6?xBx zYWpaD>f{vl^TTl3rmOdJaM0R1XJBo@8}rjS1%I7rarfiilBUJ3c^$pGUe0>)y6sp4 zgH1pFig+SNt<=kZ(0{{=@^fjR>;LgD>iF+J|KET7-+$|$-~Qhpmo}H=@i4dGTK`rk z{mc)f7u8H~tk^UP7_Q}yTPuCwh*Y0SXHLOtHW1U1OTdl}S!lgjc|5BmC@joW2O|L~ z+LR*Zb!aY@-dLKcy0w0_2xl$qtRcVrm{3MSk1|GXAP`dl;Ar zh%DrR+sGoT9@aCkX`9$ z6@Ib>+~$u0#{lM}6#;^8PSGK&k#KPU{3Ma`I!|A{`U6bf?sg_zhFtqwQkJr7(x)d) zw*Lu;JfvCrxJ+#gwv@ruK_>GZrqG#OoV_|qASN+%1OVbE8IqnrVmoab z8@4QvM>>z_LK!Cx1hR>Uo(=Cuh07#oX(Z?->!Ai*+PK9+0RS~*pm-0d7QL8&lYqqh zR{e@&Dmx~$gTeSrf{tvXApZhkm0S@AypzD(cZ^?0x6zc|NSI{lm&{clK+z(LL|v+V z;Vt1FJToYCMc_(NTuP@VcrsYbj#$fVSAgy@i$9W`Osh=4D8{#O{ zl&5HEA%t>)QF(}i0bb`vWtIfy$4kQRdD-%n&riT(2KVya*Gj3K#PU%1TR^<;DFES* zs3~w@yVibIVlx~C#$t$+5MO)@HSWsdClD=>go5x&5%_x3*FQ527pt3z;EW*-;%{}gdQp?J8B(> zKBIXZI2gYnE@kLv_cc+cZPP}wevFAPC6X`+cw)tTt(UJu8^(vT^40i(nBmE9EL}=7 z7{`2IBD518FZ#I803V&Gb#R0L5bX&?M&`i`1-Z}hiN}Vxv*<_b*(+R?dlEJ%47EV= zWjQkA$kuEYpEbwqtb!zuQrBk7}aNM!5+vy*&Snw4vt(t~|^X0}5o91MX0O z`7Dz#wLvi|dUTKnhDZvww-(k@7?ph&xPwc7Nb;Qwxr4@+mvJ98#Mlck!i%MeNUlUg zjO~nAXJX(_XA-#bDXtY5T8yazIrzeK$d~bi6r%7_TIhD6VA%O-G6LD4g9K)RIA!5i z&Ithco|tSvWZ?g{or2n+&h6Cu&6n*qK0O(!T0mTu$DYRu+Tw=0U-TcRKYuRF$7$s^ zJd4%M-Vp)$y;F3_*KBBZ=(+I4Iz}$?Wm{ldtU+g?f;$Qzu%W514kJ zzIE#u%M5O;dD&*wZ;-Qy{PILW_#{iwu~F*MK%Q_ZJTEd)B+Vwnvm42T9}l>VDOR7V zwnsDA84&qxI&`TQ4Y$*32se}6lG5b^2doe~NUF5);I8?4=^+bLnoU(#Tt$N@W?4e= zltm^tGe1pBQP69wekr|kv(8mcHlb zvcy+lV%%avb{sKdbdBot15tyG+P{CBr_qXnn;rW$NM?Rw{HD%vf1UR-=ecx8p^_`e1CUmJieG(7-|@5sV<>( zV`8IDa=Q!;LprLR5fQO)fY`>!ehnD8!@vGLL}Up<2_=V!CzVJ6R2IeaEKFp^3?%wa zxLNcY%m!$pZx-Lku+{UWm*tYRcR8O`Zk}20J3n397{9>>_!14z-r1I^+i#FM;px6- z?!5uEym%e+T4FM-w((<_tacp1d&7-<0)_?}G^PyG717*_h762#IIBRwN=0BKiIF!K z6$K_DO0qR!N8&Oo;<~U@d9)X+HW6Y4qwn#1JBR>)b>yRwEsIi!yF;BKirkGGHwG2` zF=>(pZ6f+4SsjRV#os*Xk7%Vla?4ymOF59Cw?1^LH-Z1PbDZ$U>HDc|B*VQs<7HwAeM_RQ;JxsKOSY8jHx2M;Q=x{%CnF?KELrNf}(lEcnp{01D^!o7#KhCbv? z{vH)fkhRG@3$1G(+*1pb|60pv4(A6ZBD^_|-`tSrDT82!jV68S z*@tL4?>Z+HtYZeTPk@I;rA8-@GHsKoJUyDJ9;5GF3V{?1K`Ur`JJ~qI+c~I(Z zis)OnblYtw#*ixcvcUSV*yy5ADDhQ(N!*^+dJHQm#`>`#`E7X>JQdKTlwk}O(~ATd zjqny*hwJmJx47ot`gprPqbu3(woQTQlz*P|uLiETQ{OFi!fwtZwV*n-rpLS5y3bLU z(6_i;-@0kCy1zpHx9QO~s|~@Y6swA>ZtVv#zxkq4b#m&Q^whNGS7Wk=YdCydot5iE*X3Wdqi)|9_+dp3 zwOgXQa*>INL8a>Hmu+5puB}=`@l-G~FnHsQ65UOi*FU)?>xG`pRdrjeX4~@itLLrj zL+HD@HwPS=N16HP&phpQX}M|>YK#DMk^Z43>ejc5hcN+e@nXP4PRr?7Rq5Rn-?_uO zOIw<7Z>rJSwZ)44l?{&6EYB-coqVR#)9g~ufvRW*=o%9O#jZw*;lC*%v)@7Z>U5l(FRQK05p{biwJ+AQ3aYfrt8uE=R_ zqWiub&((o*MZ#0R$xcdL@H&xU;?LVHa3w3t?jkj%!r5Cp?dRprqgSCRaHhJkl<1YmVi`_jn95D@Y8TC8M#Qy*mB5?y1kk;-qPKHOX#JLm$Wpqd=AKc42VWopu zcPNqV9!LUJn3yTRN&;e3pzq)#7-BL2fF!TU=V836KtTq-4Ldzll$A#P-c~Tk68f;H z0cZrIw8DH#vsKfSH*ZY%5Qt$p2fI#Q=TQ&&vkIt1&P>j zw_wbm@ngU4$Cx+jfWU7J`rdVAAR|K@an%z&D#K)<;Miw6rrVK9BZLL?TJpZapm+6++n# zV?|0`q>JLEjbHNz=5BGsK?*b({{WvYj`V~P%a_-E|K|*k-Mh09f-S>oNi5QrKzLMj zyGK9tn7O@_&?3>Qpf!`rDca_55Bn0i+PEUhcXP8rJs}gnFIPN=+*9y<9qS$R9 zfJ#hEyn{GfCU_8R53#VBA^Dix-wE!33Cp1L$lD0bLA-*Q;Q~(r$O(&qE8O+_-50N4 zPoZ_p??hmOiU4CJH0sAH1?v=3@E0#7=I){ z?D(;xh0CW3PextfLZsAow{#WR7N)-BfZo^?3liODoyKtfbRWOvy7EGrxI?6m#3 zo_2e8k$*(QK@X8_%T9=i49>{pQc}Q&1Zkmt2!gekT1HE|?#Xx+CPg z(GW$4=h>c1W>MG5RjZmAcLxf5LCGe$?s8}4CQO~A5lT0A^`+Yv=6uZ;kj_m9N{n3| zjvA*hFVf|@$~l9><}F-%2d>OnS$<{1oX*;Jc6Ic6TJV)Z0I_e2%3Xc?_KkUOKM4O7 zGA!cm*j3j{agM@$DH+C z#lY^DE(eruXPR(e>PqTr4Ct9;Y9rGHx+wy%7+uX^cFu%}MyGO7D2ndNgXNbgCb^u# z%3zKl-3A{RzyOhhC+#7> <> <> +<> <> <> <> diff --git a/doc/manual/es/ReleaseNotes.raw.wiki b/doc/manual/es/ReleaseNotes.raw.wiki index 0c8c096ef..9dd3c06c4 100644 --- a/doc/manual/es/ReleaseNotes.raw.wiki +++ b/doc/manual/es/ReleaseNotes.raw.wiki @@ -8,6 +8,43 @@ For more technical details, see the [[https://salsa.debian.org/freedombox-team/f The following are the release notes for each !FreedomBox version. +== FreedomBox 22.22 (2022-10-10) == + +=== Highlights === + + * privacy: Add new system app for popularity-contest + * matrix: Add fail2ban jail + +=== Other Changes === + + * *: Use privileged decorator for actions + * action_utils: Drop support for non-systemd environments + * action_utils: Drop unused progress requests from apt-get + * actions: Allow actions to be called by other users + * actions: Allow nested and top-level actions + * actions: Drop unused superuser_run and related methods + * actions: Implement getting raw output from the process + * actions: Use separate IPC for communicating results + * apache: Fix logs still going into /var/log files + * bind: Drop enabling DNSSEC (deprecated) as it is always enabled + * config: Drop ability to set hostname on systems without systemd + * config: Drop legacy migration of Apache homepage settings + * fail2ban: Make fail2ban log to journald + * firewall: Drop showing running status + * locale: Update translations for Albanian, Czech, Norwegian Bokmål, Russian, Swedish, Ukrainian + * minidlna: Use the exposed URL for diagnostic test + * openvpn: Drop RSA to ECC migration code and two-step setup + * privacy: Set vendor as !FreedomBox for dpkg and popularity-contest + * searx: Show status of public access irrespective of enabled state + * templates: Update HTML meta tags for better description and app-name + * tests: Add fixture to help in testing privileged actions + * wordpress: Update fail2ban filter + +== FreedomBox 22.21.1 (2022-10-01) == + + * locale: Update translations for Bulgarian, Ukrainian + * notification: Don't fail when formatting message strings + == FreedomBox 22.21 (2022-09-26) == * janus: Enable systemd sandboxing From 64cbcb0d0d4fd48d7bf41760ecd901851c4c6fb6 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Mon, 10 Oct 2022 21:57:23 -0400 Subject: [PATCH 90/90] Release v22.22 to unstable Signed-off-by: James Valleroy --- debian/changelog | 111 +++++++++++++++++++++++++++++++++++++++++++++ plinth/__init__.py | 2 +- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 798868c2b..abb2ec76e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,114 @@ +freedombox (22.22) unstable; urgency=medium + + [ Michael Breidenbach ] + * Translated using Weblate (Swedish) + + [ Tymofii Lytvynenko ] + * Translated using Weblate (Ukrainian) + * Translated using Weblate (Ukrainian) + * Translated using Weblate (Ukrainian) + + [ Jiří Podhorecký ] + * Translated using Weblate (Czech) + + [ Sunil Mohan Adapa ] + * templates: Update HTML meta tags for better description and app-name + * doc: dev: Minor example code refactor + * actions: Allow nested and top-level actions + * actions: Use separate IPC for communicating results + * actions: Implement getting raw output from the process + * actions: Allow actions to be called by other users + * config: Drop ability to set hostname on systems without systemd + * dynamicdns: Check action script with flake8 + * tests: Add fixture to help in testing privileged actions + * apache: Use privileged decorator for actions + * bepasty: Use privileged decorator for actions + * bind: Use privileged decorator for actions + * calibre: Use privileged decorator for actions + * config: Minor update to privileged method signature + * config: Use privileged decorator for actions + * config: Use privileged decorator for set-hostname action + * config: Use privileged decorator for set domainname action + * config: Minor refactor + * coturn: Use privileged decorator for actions + * datetime: Use privileged decorator for actions + * deluge: Use privileged decorator for actions + * dynamicdns: Use privileged decorator for actions + * ejabberd: Use privileged decorator for actions + * email: Use privileged decorator for actions + * firewall: Use privileged decorator, drop showing running status + * gitweb: Use privileged decorator for actions + * help: Use privileged decorator for actions + * i2p: Use privileged decorator for actions + * ikiwiki: Use privileged decorator for actions + * infinoted: Use privileged decorator for actions + * letsencrypt: Use privileged decorator for actions + * matrixsynapse: Use privileged decorator for actions + * mediawiki: Use privileged decorator for actions + * minetest: Use privileged decorator for actions + * minidlna: Use privileged decorator for actions + * minidlna: Use the exposed URL for diagnostic test + * networks: Use privileged decorator for actions + * openvpn: Use privileged decorator for actions + * openvpn: Drop RSA to ECC migration code and two-step setup + * pagekite: Use privileged decorator for actions + * power: Use privileged decorator for actions + * quassel: Use privileged decorator for actions + * radicale: Use privileged decorator for actions + * roundcube: Minor update to comment in privileged actions + * searx: Use privileged decorator for actions + * searx: Show status of public access irrespective of enabled state + * security: Use privileged decorator for actions + * shadowsocks: Use privileged decorator for actions + * sharing: Use privileged decorator for actions + * snapshot: Use privileged decorator for actions + * ssh: Use privileged decorator for actions + * sso: Use privileged decorator for actions + * syncthing: Use privileged decorator for actions + * tor: Use privileged decorator for actions + * transmission: Minor update to privileged method signature + * ttrss: Use privileged decorator for actions + * upgrades: Use privileged decorator for actions + * wireguard: Us privileged decorator for actions + * wordpress: Use privileged decorator for actions + * zoph: Use privileged decorator for actions + * backups: Use privileged decorator for sshfs actions + * samba: Use privileged decorator for actions + * storage: Use privileged decorator for actions + * users: Use privileged decorator for actions + * *: Use privileged decorator for service actions + * backups: Use privileged decorator for backup actions + * *: Use privileged decorator for package actions + * actions: Drop unused superuser_run and related methods + * action_utils: Drop unused progress requests from apt-get + * bind: Drop enabling DNSSEC (deprecated) as it is always enabled + * config: Drop legacy migration of Apache homepage settings + * action_utils: Drop support for non-systemd environments + * apache: Fix logs still going into /var/log files + * wordpress: Update fail2ban filter + * fail2ban: Make fail2ban log to journald + * privacy: Set vendor as FreedomBox for dpkg and popularity-contest + + [ Petter Reinholdtsen ] + * Translated using Weblate (Norwegian Bokmål) + + [ Besnik Bleta ] + * Translated using Weblate (Albanian) + * Translated using Weblate (Albanian) + + [ nbenedek ] + * matrix: Add fail2ban jail + * privacy: Add new system app for popularity-contest + + [ Nikita Epifanov ] + * Translated using Weblate (Russian) + + [ James Valleroy ] + * locale: Update translation strings + * doc: Fetch latest manual + + -- James Valleroy Mon, 10 Oct 2022 21:38:11 -0400 + freedombox (22.21.1) unstable; urgency=medium [ Andrij Mizyk ] diff --git a/plinth/__init__.py b/plinth/__init__.py index 856676dbd..00f79f98b 100644 --- a/plinth/__init__.py +++ b/plinth/__init__.py @@ -3,4 +3,4 @@ Package init file. """ -__version__ = '22.21.1' +__version__ = '22.22'