From ebff96af785aa38db1a9dc3ed97ab49d1da201e2 Mon Sep 17 00:00:00 2001
From: Burak Yavuz
SSH key-based authentication is not yet "
"possible."
-msgstr "SSH 服务器的密码。
基于密钥的 SSH 验证暂不支持。"
+msgstr "SSH 服务器的密码。
基于 SSH 密钥的身份验证尚不可能。"
#: plinth/modules/backups/forms.py:267
msgid "Remote backup repository already exists."
@@ -465,8 +465,8 @@ msgid ""
"To restore a backup on a new %(box_name)s you need the ssh credentials and, "
"if chosen, the encryption passphrase."
msgstr ""
-"这个存储库的凭证存储在您的 %(box_name)s。
要在新的 %(box_name)s 中恢复备"
-"份,你需要这个 ssh 凭证,如果当时选择了加密,则也需要密码。"
+"这个存储库的凭证存储在您的 %(box_name)s。
要在新的 %(box_name)s 上恢复备份,你需要这个 ssh "
+"凭证,如果当时选择了加密,则也需要加密口令。"
#: plinth/modules/backups/templates/backups_add_remote_repository.html:28
msgid "Create Location"
@@ -569,8 +569,9 @@ msgid ""
" "
msgstr ""
"\n"
-" 上传从另一个%(box_name)s下载的备份文件,以恢复其内容。\n"
-"\t您可以选择您希望在上传备份文件后恢复的应用程序。\n"
+" 上传一个从另一个 %(box_name)s 下载的备份文件来还原其\n"
+" 内容。 你可以选择上传备份文件后希望还原的\n"
+" 应用。\n"
" "
#: plinth/modules/backups/templates/backups_upload.html:27
@@ -651,7 +652,7 @@ msgstr "上传并且储存一个备份"
#: plinth/modules/backups/views.py:194
msgid "Restored files from backup."
-msgstr "从备份中恢复文件"
+msgstr "从备份中恢复了文件。"
#: plinth/modules/backups/views.py:222
msgid "No backup file found."
@@ -933,7 +934,7 @@ msgstr "转发器"
#: plinth/modules/bind/forms.py:21
msgid ""
"A list DNS servers, separated by space, to which requests will be forwarded"
-msgstr "DNS 服务器列表,请求将会被转发到这里,使用空格分割。"
+msgstr "DNS 服务器列表,请求将会被转发到这里,使用空格分割"
#: plinth/modules/bind/forms.py:25
msgid "Enable DNSSEC"
@@ -1334,7 +1335,7 @@ msgstr "无效的STUN/TURN服务器URI列表"
#: plinth/modules/coturn/templates/coturn.html:15
msgid "Use the following URLs to configure your communication server:"
-msgstr "使用以下URL来配置你的通信服务器。"
+msgstr "使用以下 URL 来配置你的通信服务器:"
#: plinth/modules/coturn/templates/coturn.html:24
#, fuzzy
@@ -1384,18 +1385,10 @@ msgid "Deluge is a BitTorrent client that features a Web UI."
msgstr "Deluge 是一个有网页界面的 BitTorrent 客户端。"
#: plinth/modules/deluge/__init__.py:23
-#, fuzzy
-#| msgid ""
-#| "When enabled, the Deluge web client will be available from /deluge path on the web server. The default password is "
-#| "'deluge', but you should log in and change it immediately after enabling "
-#| "this service."
msgid ""
"The default password is 'deluge', but you should log in and change it "
"immediately after enabling this service."
-msgstr ""
-"启用后,Deluge 网页客户端可以从 /deluge 路径访问网页"
-"服务器。默认密码是“deluge”,但是你需要在启用此服务以后立刻登录并修改它。"
+msgstr "默认密码是“deluge”,但是你需要在启用此服务以后立刻登录并修改它。"
#: plinth/modules/deluge/__init__.py:44
#: plinth/modules/transmission/__init__.py:49
@@ -1409,9 +1402,7 @@ msgstr "启用 Deluge"
#: plinth/modules/deluge/__init__.py:50
#: plinth/modules/transmission/__init__.py:55
msgid "BitTorrent Web Client"
-msgstr ""
-"BitTorrent 网页客户端\n"
-"(Deluge)"
+msgstr "BitTorrent 网页客户端"
#: plinth/modules/deluge/forms.py:20 plinth/modules/transmission/forms.py:21
msgid "Download directory"
@@ -1441,10 +1432,8 @@ msgstr "通过了"
#: plinth/modules/diagnostics/__init__.py:98
#: plinth/modules/email_server/templates/email_server.html:35
#: plinth/modules/networks/views.py:49
-#, fuzzy
-#| msgid "Setup failed."
msgid "failed"
-msgstr "安装失败。"
+msgstr "失败"
#: plinth/modules/diagnostics/__init__.py:99
#: plinth/modules/email_server/templates/email_server.html:33
@@ -1481,8 +1470,8 @@ msgid ""
"System is low on memory: {percent_used}% used, {memory_available} "
"{memory_available_unit} free. {advice_message}"
msgstr ""
-"系统内存不足。{percent_used}%已用,{memory_available} {memory_available_unit}"
-"可用。{advice_message}。"
+"系统内存不足:已使用 {percent_used},{memory_available} "
+"{memory_available_unit}可用。{advice_message}"
#: plinth/modules/diagnostics/__init__.py:233
msgid "Low Memory"
@@ -1566,8 +1555,7 @@ msgstr "dandelion*"
msgid ""
"It is an unofficial webview based client for the community-run, distributed "
"social network diaspora*"
-msgstr ""
-"它是一个非官方的基于webview的客户端,用于社区运营的分布式社交网络diaspora*。"
+msgstr "它是一款非官方的基于 webview 的客户端,用于社区运营的分布式社交网络 diaspora*"
#: plinth/modules/diaspora/templates/diaspora-post-setup.html:16
#, python-format
@@ -1633,11 +1621,9 @@ msgid ""
"Internet asks for your DNS name, they will get a response with your current "
"IP address."
msgstr ""
-"解决方案是为您的 IP 地址分配一个 DNS 名称,并在您的互联网提供商每次更改 IP 时"
-"更新 DNS 名称。 动态 DNS 可以将当前的公共 IP 地址推送到 GnuDIP 服务器。 之后,服务器会"
-"将您的 DNS 名称分配给新的 IP,如果互联网上的某人要求您的 DNS 名称,他们将收到"
-"一个带有您当前 IP 地址的响应。"
+"解决方案是为您的 IP 地址分配一个 DNS 名称,并在您的互联网提供商每次更改 IP 时更新 DNS 名称。 动态 DNS 允许你将当前的公共 IP "
+"地址推送到 GnuDIP"
+"a> 服务器。 之后,服务器会将您的 DNS 名称分配给新的 IP,如果互联网上的某人要求您的 DNS 名称,他们将从您当前 IP 地址收到响应。"
#: plinth/modules/dynamicdns/__init__.py:52
msgid "Dynamic DNS Client"
@@ -1713,7 +1699,7 @@ msgstr ""
#: plinth/modules/dynamicdns/forms.py:62
msgid "The username that was used when the account was created."
-msgstr "账户创建时使用的用户名"
+msgstr "创建账户时使用的用户名。"
#: plinth/modules/dynamicdns/forms.py:65
msgid "GnuDIP"
@@ -1787,23 +1773,16 @@ msgid "Please provide a password"
msgstr "请提供一个密码"
#: plinth/modules/dynamicdns/templates/dynamicdns.html:12
-#, fuzzy
-#| msgid ""
-#| "If you are looking for a free dynamic DNS account, you may find a free "
-#| "GnuDIP service at gnudip.datasystems24.net 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."
"freedombox.org or you may find free update URL based services at freedns.afraid.org."
msgstr ""
-"如果您正在寻找一个免费的动态 DNS 帐户,您可以在 gnudip.datasystems24.net 找到免费的 "
-"GnuDIP 服务,或您可以在 "
-"freedns.afraid.org 找到免费更新网址服务。"
+"如果您正在寻找一个免费的动态 DNS 帐户,您可以在ddns.freedombox.org 找到免费的 GnuDIP 服务,或您可以在 freedns.afraid.org "
+"找到免费更新网址服务。"
#: plinth/modules/dynamicdns/templates/dynamicdns.html:23
#, python-format
@@ -1889,19 +1868,16 @@ msgstr ""
"ejabberd。"
#: plinth/modules/ejabberd/__init__.py:34
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "To actually communicate, you can use the web client or any other XMPP "
-#| "client."
+#, python-brace-format
msgid ""
"To actually communicate, you can use the web client"
"a> or any other XMPP client. When enabled, ejabberd can be accessed by "
"any user with a {box_name} login."
msgstr ""
-"要实际沟通,您可以使用 web 客户端或任何其他 XMPP 客户端。"
+"要实际沟通,您可以使用 web 客户端或任何其他 XMPP 客户端。启用后,任何有 {box_name} 登录的用户均可访问 ejabberd。"
#: plinth/modules/ejabberd/__init__.py:42
#, python-brace-format
@@ -2245,16 +2221,14 @@ msgid "Firewall"
msgstr "防火墙"
#: plinth/modules/firewall/components.py:134
-#, fuzzy, python-brace-format
-#| msgid "Service discovery server is not running"
+#, python-brace-format
msgid "Port {name} ({details}) available for internal networks"
-msgstr "服务发现服务未运行"
+msgstr "内网端口 {name}({details})可用"
#: plinth/modules/firewall/components.py:142
-#, fuzzy, python-brace-format
-#| msgid "Service discovery server is not running"
+#, python-brace-format
msgid "Port {name} ({details}) available for external networks"
-msgstr "服务发现服务未运行"
+msgstr "外网端口 {name}({details})可用"
#: plinth/modules/firewall/components.py:147
#, python-brace-format
@@ -2269,9 +2243,9 @@ 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”命令运行它。"
+"防火墙守护程序未运行。请运行它。防火墙默认在 %(box_name)s 上启用。在任何基于 Debian 的系统(例如 "
+"%(box_name)s)上,要运行它,您可以使用命令 “service firewalld start” ,在使用 systemd 的系统上则使用 “"
+"systemctl start firewalld”命令。"
#: plinth/modules/firewall/templates/firewall.html:35
msgid "Service/Port"
@@ -2386,16 +2360,12 @@ msgid "Simple Git Hosting"
msgstr ""
#: plinth/modules/gitweb/forms.py:59
-#, fuzzy
-#| msgid "Invalid hostname"
msgid "Invalid repository URL."
-msgstr "无效的主机名"
+msgstr "无效的存储库 URL。"
#: plinth/modules/gitweb/forms.py:69
-#, fuzzy
-#| msgid "Invalid hostname"
msgid "Invalid repository name."
-msgstr "无效的主机名"
+msgstr "无效的存储库名称。"
#: plinth/modules/gitweb/forms.py:77
#, fuzzy
@@ -2415,10 +2385,8 @@ msgid "Optional, for displaying on Gitweb."
msgstr ""
#: plinth/modules/gitweb/forms.py:86
-#, fuzzy
-#| msgid "Repository removed."
msgid "Repository's owner name"
-msgstr "储存库被移除。"
+msgstr "储存库所有者名称"
#: plinth/modules/gitweb/forms.py:91
#, fuzzy
@@ -2431,10 +2399,8 @@ msgid "Allow only authorized users to access this repository."
msgstr ""
#: plinth/modules/gitweb/forms.py:113 plinth/modules/gitweb/forms.py:155
-#, fuzzy
-#| msgid "This service already exists"
msgid "A repository with this name already exists."
-msgstr "此服务已存在"
+msgstr "已存在同名存储库。"
#: plinth/modules/gitweb/forms.py:126
#, fuzzy
@@ -2474,26 +2440,22 @@ msgid "Create repository"
msgstr "创建用户"
#: plinth/modules/gitweb/templates/gitweb_configure.html:26
-#, fuzzy
-#| msgid "Tor relay port available"
msgid "No repositories available."
-msgstr "Tor 中继端口可用"
+msgstr "无存储库可用。"
#: plinth/modules/gitweb/templates/gitweb_configure.html:35
-#, fuzzy, python-format
-#| msgid "Go to site %(site)s"
+#, python-format
msgid "Go to repository %(repo.name)s"
-msgstr "转到站点 %(site)s"
+msgstr "转到存储库 %(repo.name)s"
#: plinth/modules/gitweb/templates/gitweb_configure.html:42
msgid "Cloning…"
msgstr ""
#: plinth/modules/gitweb/templates/gitweb_configure.html:59
-#, fuzzy, python-format
-#| msgid "Delete user %(username)s"
+#, python-format
msgid "Delete repository %(repo.name)s"
-msgstr "删除用户 %(username)s"
+msgstr "删除存储库 %(repo.name)s"
#: plinth/modules/gitweb/templates/gitweb_delete.html:12
#, fuzzy, python-format
@@ -2566,25 +2528,22 @@ msgstr "贡献"
#: plinth/modules/help/templates/help_about.html:17
#: plinth/modules/upgrades/templates/upgrades_configure.html:26
-#, fuzzy, python-format
-#| msgid "You are running Plinth version %(version)s."
+#, python-format
msgid "You are running %(os_release)s and %(box_name)s version %(version)s."
-msgstr "您正在运行 Plinth 版本 %(version)s。"
+msgstr "您正在运行 %(os_release)s 和 %(version)s 版的 %(box_name)s。"
#: plinth/modules/help/templates/help_about.html:23
-#, fuzzy, python-format
-#| msgid "There is a new version available."
+#, python-format
msgid ""
"There is a new %(box_name)s version available"
"a>."
-msgstr "有新版本可用"
+msgstr "有新的 %(box_name)s 版本 可用。"
#: plinth/modules/help/templates/help_about.html:28
#: plinth/modules/upgrades/templates/upgrades_configure.html:37
-#, fuzzy, python-format
-#| msgid "%(box_name)s Setup"
+#, python-format
msgid "%(box_name)s is up to date."
-msgstr "%(box_name)s 安装程序"
+msgstr "%(box_name)s 已是最新。"
#: plinth/modules/help/templates/help_about.html:35
#, python-format
@@ -2637,10 +2596,8 @@ msgstr ""
"FreedomBox\">%(box_name)s Wiki。"
#: plinth/modules/help/templates/help_about.html:78
-#, fuzzy
-#| msgid "Learn more..."
msgid "Learn more"
-msgstr "了解更多……"
+msgstr "了解更多"
#: plinth/modules/help/templates/help_base.html:21
#: plinth/modules/help/templates/help_index.html:61
@@ -2747,10 +2704,9 @@ msgid ""
"oftc.net/?randomnick=1&channels=freedombox&prompt=1\"> #freedombox "
"channel using the IRC web interface."
msgstr ""
-"许多 %(box_name)s 的贡献者和用户也活跃在 IRC 网络 irc.oftc.net 上。可以使用 "
-"IRC 接口连接加入 #freedombox 频道并在上面请求"
-"帮助。"
+"许多 %(box_name)s 贡献者和用户也活跃在 IRC 网络 irc.oftc.net 上。可以使用 IRC 网页界面加入 #freedombox 频道并在上面请求帮助。"
#: plinth/modules/help/templates/help_manual.html:18
#, fuzzy
@@ -2903,20 +2859,12 @@ msgid ""
msgstr ""
#: plinth/modules/ikiwiki/__init__.py:22
-#, fuzzy
-#| 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. When enabled, the blogs and "
-#| "wikis will be available from /ikiwiki."
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 ""
-"ikiwiki是一个简单的 wiki 和博客应用程序。它支持几种轻量级标记语言,包括 "
-"Markdown 和常见的博客功能,如评论和 RSS 源。启用后,博客和 Wiki 将可从 /ikiwiki 访问。"
+"ikiwiki是一个简单的 wiki 和博客应用程序。它支持几种轻量级标记语言,包括 Markdown 和常见的博客功能,如评论和 RSS 源。"
#: plinth/modules/ikiwiki/__init__.py:26
#, python-brace-format
@@ -3008,16 +2956,14 @@ msgid "Could not create blog: {error}"
msgstr "不能创建博客:{error}"
#: plinth/modules/ikiwiki/views.py:101
-#, fuzzy, python-brace-format
-#| msgid "{name} deleted."
+#, python-brace-format
msgid "{title} deleted."
-msgstr "{name} 已删除。"
+msgstr "{title} 已被删除。"
#: plinth/modules/ikiwiki/views.py:105
-#, fuzzy, python-brace-format
-#| msgid "Could not delete {name}: {error}"
+#, python-brace-format
msgid "Could not delete {title}: {error}"
-msgstr "不能删除 {name}:{error}"
+msgstr "无法删除 {title}: {error}"
#: plinth/modules/infinoted/__init__.py:21
msgid "infinoted is a server for Gobby, a collaborative text editor."
@@ -3048,23 +2994,15 @@ msgid "Gobby"
msgstr ""
#: plinth/modules/infinoted/manifest.py:12
-#, fuzzy
-#| msgid "infinoted is a server for Gobby, a collaborative text editor."
msgid "Gobby is a collaborative text editor"
-msgstr "infinoted 是一个 Gobby 服务器,Gobby 是一个协作化的文本编辑器。"
+msgstr "Gobby 是一个协作化的文本编辑器"
#: plinth/modules/infinoted/manifest.py:15
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "To use it, download Gobby, "
-#| "desktop client and install it. Then start Gobby and select \"Connect to "
-#| "Server\" and enter your {box_name}'s domain name."
+#, python-brace-format
msgid ""
"Start Gobby and select \"Connect to Server\" and enter your {box_name}'s "
"domain name."
-msgstr ""
-"要使用它, 下载 Gobby 的桌面客户"
-"端并安装。然后启动 Gobby 并选择“连接到服务器”并书入你的 {box_name} 域名即可。"
+msgstr "启动 Gobby ,选择“连接到服务器”并输入你的 {box_name} 域名。"
#: plinth/modules/jsxc/__init__.py:21
msgid ""
@@ -3077,14 +3015,8 @@ msgid "JSXC"
msgstr ""
#: plinth/modules/jsxc/__init__.py:45
-#, fuzzy
-#| msgid ""
-#| "Chat Client \n"
-#| " (JSXC)"
msgid "Chat Client"
-msgstr ""
-"聊天客户端\n"
-"(JSXC)"
+msgstr "聊天客户端"
#: plinth/modules/jsxc/templates/jsxc_launch.html:117
#: plinth/templates/base.html:247
@@ -3194,22 +3126,18 @@ msgid "Obtain"
msgstr "获取"
#: plinth/modules/letsencrypt/templates/letsencrypt.html:112
-#, fuzzy, python-format
-#| msgid ""
-#| "No domains have been configured. Configure domains to be able to obtain "
-#| "certificates for them."
+#, python-format
msgid ""
"No domains have been configured. Configure "
"domains to be able to obtain certificates for them."
-msgstr "没有配置域名。配置域名可以为它们获得相应的证书。"
+msgstr "还没有配置域名。配置域名可以为它们获得相应的证书。"
#: plinth/modules/letsencrypt/views.py:41
-#, fuzzy, python-brace-format
-#| msgid "Certificate successfully revoked for domain {domain}"
+#, python-brace-format
msgid ""
"Certificate successfully revoked for domain {domain}.This may take a few "
"moments to take effect."
-msgstr "成功为域名 {domain} 吊销证书"
+msgstr "成功吊销了域名 {domain} 的证书。可能需要一会儿才能生效。"
#: plinth/modules/letsencrypt/views.py:47
#, python-brace-format
@@ -3258,14 +3186,8 @@ msgid ""
msgstr ""
#: plinth/modules/matrixsynapse/__init__.py:70
-#, fuzzy
-#| msgid ""
-#| "Chat Server \n"
-#| " (Matrix Synapse)"
msgid "Matrix Synapse"
-msgstr ""
-"聊天服务器\n"
-"(Matrix Synapse)"
+msgstr "Matrix Synapse"
#: plinth/modules/matrixsynapse/forms.py:16
#, fuzzy
@@ -3315,19 +3237,14 @@ msgid ""
msgstr ""
#: plinth/modules/matrixsynapse/templates/matrix-synapse.html:15
-#, fuzzy, python-format
-#| msgid ""
-#| "Your XMPP server domain is set to %(domainname)s. User IDs will "
-#| "look like username@%(domainname)s. You can setup your domain on "
-#| "the system Configure page."
+#, python-format
msgid ""
"The Matrix server domain is set to %(domain_name)s. User IDs will "
"look like @username:%(domain_name)s. Changing the domain name after "
"the initial setup is currently not supported."
msgstr ""
-"XMPP 服务器域名可以设置为 %(domainname)s。用户 ID 类似于 username@"
-"%(domainname)s。你可以在系统的配置中设"
-"置你的域名。"
+"XMPP 服务器域名已设置为 %(domain_name)s 。用户 ID 看起来像是这样 "
+"@username:%(domain_name)s。尚不支持在初始安装后更改域名。"
#: plinth/modules/matrixsynapse/templates/matrix-synapse.html:22
msgid ""
@@ -3472,10 +3389,8 @@ msgid "Default skin changed"
msgstr "设置未改变"
#: plinth/modules/mediawiki/views.py:90
-#, fuzzy
-#| msgid "{name} deleted."
msgid "Server URL updated"
-msgstr "{name} 已删除。"
+msgstr "已更新服务器 URL"
#: plinth/modules/minetest/__init__.py:34
#, python-brace-format
@@ -3494,28 +3409,18 @@ msgid "Minetest"
msgstr ""
#: plinth/modules/minetest/__init__.py:60
-#, fuzzy
-#| msgid ""
-#| "Block Sandbox \n"
-#| " (Minetest)"
msgid "Block Sandbox"
-msgstr ""
-"方块沙盒\n"
-"(Minetest)"
+msgstr "方块沙盒"
#: plinth/modules/minetest/forms.py:13
msgid "Maximum number of players"
msgstr "最大玩家数量"
#: plinth/modules/minetest/forms.py:15
-#, fuzzy
-#| msgid ""
-#| "You can change the maximum number of players playing "
-#| "minetest at a single instance of time"
msgid ""
"You can change the maximum number of players playing minetest at a single "
"instance of time."
-msgstr "你可以修改 minetest 单位时间单一实例里的最大玩家数量"
+msgstr "你可以修改 minetest 单位时间单一实例里的最大玩家数量。"
#: plinth/modules/minetest/forms.py:19
msgid "Enable creative mode"
@@ -3537,24 +3442,16 @@ msgid "Enable PVP"
msgstr "启用玩家对战(PVP)"
#: plinth/modules/minetest/forms.py:26
-#, fuzzy
-#| msgid ""
-#| "Enabling Player Vs Player will allow players to "
-#| "damage other players"
msgid "Enabling Player Vs Player will allow players to damage other players."
-msgstr "启用玩家对战模式允许玩家伤害另一个玩家"
+msgstr "启用玩家对战模式允许玩家伤害另一个玩家。"
#: plinth/modules/minetest/forms.py:30
msgid "Enable damage"
msgstr "启用伤害"
#: plinth/modules/minetest/forms.py:31
-#, fuzzy
-#| msgid ""
-#| "When disabled, players cannot die or receive damage "
-#| "of any kind"
msgid "When disabled, players cannot die or receive damage of any kind."
-msgstr "禁用时,玩家间不能互相伤害也不能死"
+msgstr "禁用后,玩家不能死或受到任何伤害。"
#: plinth/modules/minetest/templates/minetest.html:17
#: plinth/modules/networks/forms.py:54 plinth/modules/networks/forms.py:90
@@ -3874,14 +3771,8 @@ msgid "Mumble"
msgstr ""
#: plinth/modules/mumble/__init__.py:49
-#, fuzzy
-#| msgid ""
-#| "Voice Chat \n"
-#| " (Mumble)"
msgid "Voice Chat"
-msgstr ""
-"语音聊天\n"
-"(Mumble)"
+msgstr "语音聊天"
#: plinth/modules/mumble/forms.py:30
#, fuzzy
@@ -4187,10 +4078,9 @@ msgid "Open"
msgstr "打开"
#: plinth/modules/networks/forms.py:310
-#, fuzzy, python-brace-format
-#| msgid "Direct connection to the Internet."
+#, python-brace-format
msgid "Specify how your {box_name} is connected to your network"
-msgstr "直接连接到互联网。"
+msgstr "指定 {box_name} 连接到网络的方式"
#: plinth/modules/networks/forms.py:317
#, python-brace-format
@@ -4640,16 +4530,13 @@ msgstr ""
#: plinth/modules/networks/templates/internet_connectivity_main.html:41
#: plinth/modules/networks/templates/network_topology_main.html:41
-#, fuzzy
-#| msgid "Update"
msgid "Update..."
-msgstr "更新"
+msgstr "更新…"
#: plinth/modules/networks/templates/network_topology_content.html:10
-#, fuzzy, python-format
-#| msgid "Direct connection to the Internet."
+#, python-format
msgid "How is Your %(box_name)s Connected to the Internet?"
-msgstr "直接连接到互联网。"
+msgstr "你的 %(box_name)s 是如何连接到互联网的?"
#: plinth/modules/networks/templates/network_topology_content.html:16
#, python-format
@@ -4882,10 +4769,8 @@ msgid "DHCP client error"
msgstr ""
#: plinth/modules/networks/views.py:72
-#, fuzzy
-#| msgid "Archive deleted."
msgid "DHCP client failed"
-msgstr "归档已删除。"
+msgstr "DHCP 客户端失败"
#: plinth/modules/networks/views.py:74
msgid "shared connection service failed to start"
@@ -5127,24 +5012,15 @@ msgid "Profile"
msgstr "配置文件"
#: plinth/modules/openvpn/templates/openvpn.html:25
-#, 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. See documentation on recommended clients and instructions on "
-#| "how to configure them."
+#, 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."
msgstr ""
-"要连接到 %(box_name)s 的VPN,您需要下载配置文件并将其提供给您的移动或桌面计算"
-"机上的 OpenVPN 客户端。OpenVPN 客户端适用于大多数平台。请参阅有关推荐客户的 "
-"文档 以及有关如何配置它们的说明。"
+"要连接到 %(box_name)s 的VPN,您需要下载配置文件并将其提供给移动或桌面计算机上的 OpenVPN 客户端。OpenVPN "
+"客户端适用于大多数平台。要查看推荐的客户端及配置说明请点击上方的 “了解更多…”。"
#: plinth/modules/openvpn/templates/openvpn.html:35
#, python-format
@@ -5469,8 +5345,8 @@ msgid ""
"enhancing privacy, modifying web page data and HTTP headers, controlling "
"access, and removing ads and other obnoxious Internet junk. "
msgstr ""
-"Privoxy 是一个非缓存Web代理,具有高级过滤功能,用于增强隐私,修改网页数据和 "
-"HTTP 标头,控制访问,以及删除广告和其他令人讨厌的互联网垃圾。"
+"Privoxy 是一个非缓存 Web 代理,具有高级过滤功能,用于增强隐私,修改网页数据和 HTTP "
+"标头,控制访问,以及删除广告和其他令人讨厌的互联网垃圾。 "
#: plinth/modules/privoxy/__init__.py:28
#, python-brace-format
@@ -5481,10 +5357,9 @@ msgid ""
"config.privoxy.org\">http://config.privoxy.org/ or http://p.p."
msgstr ""
-"通过将浏览器代理设置修改为使用 {box_name} 的主机名(或 IP 地址)和端口 8118,"
-"这样就可以使用 Privoxy。使用 Privoxy 时,您可以在 http://config.privoxy.org/ 或 http://p.p 中查看其配置详细信息和文档"
+"将浏览器代理设置修改为使用 {box_name} 的主机名(或 IP 地址)和端口 8118,这样就可以使用 Privoxy。使用 Privoxy 时,"
+"您可以在 http://config.privoxy.org/ 或 "
+"http://p.p 中查看其配置详细信息和文档。"
#: plinth/modules/privoxy/__init__.py:52
#, fuzzy
@@ -5576,36 +5451,26 @@ msgid "Radicale"
msgstr ""
#: plinth/modules/radicale/__init__.py:56
-#, fuzzy
-#| msgid ""
-#| "Calendar and Addressbook \n"
-#| " (Radicale)"
msgid "Calendar and Addressbook"
-msgstr ""
-"日历和通讯录\n"
-"(Radicale)"
+msgstr "日历和通讯录"
#: plinth/modules/radicale/forms.py:14
msgid "Only the owner of a calendar/addressbook can view or make changes."
msgstr "只有日历/通训录的所有者可以查看或做出改动。"
#: plinth/modules/radicale/forms.py:18
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "Any user can view any calendar/addressbook, but only the owner can make "
-#| "changes."
+#, python-brace-format
msgid ""
"Any user with a {box_name} login can view any calendar/addressbook, but only "
"the owner can make changes."
-msgstr "任何用户都可以查看任何日历/通训录,但是只有所有者可以作出修改。"
+msgstr "任何有 {box_name} 登录的用户都可以查看任何日历/通训录,但是只有所有者可以作出修改。"
#: plinth/modules/radicale/forms.py:23
-#, fuzzy, python-brace-format
-#| msgid "Any user can view or make changes to any calendar/addressbook."
+#, python-brace-format
msgid ""
"Any user with a {box_name} login can view or make changes to any calendar/"
"addressbook."
-msgstr "任何用户都可以查看和修改任何日历/通训录。"
+msgstr "任何有 {box_name} 登录的用户都可以查看和修改任何日历/通讯录。"
#: plinth/modules/radicale/forms.py:30
#, fuzzy
@@ -5666,13 +5531,6 @@ msgstr ""
"索到拼写检查的完整功能。"
#: plinth/modules/roundcube/__init__.py:25
-#, fuzzy
-#| msgid ""
-#| "You can access Roundcube from /roundcube. "
-#| "Provide the username and password of the email account you wish to access "
-#| "followed by the domain name of the IMAP server for your email provider, "
-#| "like imap.example.com. For IMAP over SSL (recommended), "
-#| "fill the server field like imaps://imap.example.com."
msgid ""
"You can use it by providing the username and password of the email account "
"you wish to access followed by the domain name of the IMAP server for your "
@@ -5680,10 +5538,9 @@ msgid ""
"(recommended), fill the server field like imaps://imap.example.com"
"code>."
msgstr ""
-"您可以从 /roundcube 访问 Roundcube。提供您要访问的"
-"电子邮件帐户的用户名和密码,然后输入您的电子邮件提供商的 IMAP 服务器的域名,"
-"如 imap.example.com。对于基于 SSL 的 IMAP(建议),服务器填写为"
-"类似 imaps://imap.example.com。"
+"可以通过提供你希望访问的电子邮件账户的用户名和密码,以及您的电子邮件提供商的 IMAP 服务器域名,像是 imap.example."
+"com。对于 IMAP over SSL (推荐),应该填入类似 imaps://imap.example.com"
+"code> 的地址。"
#: plinth/modules/roundcube/__init__.py:30
msgid ""
@@ -5700,14 +5557,8 @@ msgstr ""
"google.com/settings/security/lesssecureapps)中启用“安全性较低的应用”。"
#: plinth/modules/roundcube/__init__.py:54
-#, fuzzy
-#| msgid ""
-#| "Email Client \n"
-#| " (Roundcube)"
msgid "Email Client"
-msgstr ""
-"邮件客户端\n"
-"(Roundcube)"
+msgstr "邮件客户端"
#: plinth/modules/samba/__init__.py:27
msgid ""
@@ -5865,22 +5716,18 @@ msgid "Share enabled."
msgstr "{name} 已删除。"
#: plinth/modules/samba/views.py:107
-#, fuzzy, python-brace-format
-#| msgid "Error installing application: {error}"
+#, python-brace-format
msgid "Error enabling share: {error_message}"
-msgstr "安装应用程序出错:{error}"
+msgstr "启用分享时出错:{error_message}"
#: plinth/modules/samba/views.py:112
-#, fuzzy
-#| msgid "Shared"
msgid "Share disabled."
-msgstr "共享"
+msgstr "已禁用共享。"
#: plinth/modules/samba/views.py:117
-#, fuzzy, python-brace-format
-#| msgid "Error installing application: {error}"
+#, python-brace-format
msgid "Error disabling share: {error_message}"
-msgstr "安装应用程序出错:{error}"
+msgstr "禁用共享出错:{error_message}"
#: plinth/modules/searx/__init__.py:22
msgid ""
@@ -6039,24 +5886,12 @@ msgid "Current Vulnerabilities"
msgstr ""
#: plinth/modules/security/templates/security_report.html:47
-#, fuzzy
-#| msgid ""
-#| "Block Sandbox \n"
-#| " (Minetest)"
msgid "Sandboxed"
-msgstr ""
-"方块沙盒\n"
-"(Minetest)"
+msgstr "方块沙盒"
#: plinth/modules/security/templates/security_report.html:48
-#, fuzzy
-#| msgid ""
-#| "Block Sandbox \n"
-#| " (Minetest)"
msgid "Sandbox Coverage"
-msgstr ""
-"方块沙盒\n"
-"(Minetest)"
+msgstr "沙盒覆盖"
#: plinth/modules/security/templates/security_report.html:58
msgid "N/A"
@@ -6073,10 +5908,8 @@ msgid "No"
msgstr ""
#: plinth/modules/security/templates/security_report.html:69
-#, fuzzy
-#| msgid "is not running"
msgid "Not running"
-msgstr " 未运行"
+msgstr "未运行"
#: plinth/modules/security/views.py:56
#, python-brace-format
@@ -6092,31 +5925,18 @@ msgid "Shaarli allows you to save and share bookmarks."
msgstr "Shaarli 允许您保存和共享书签。"
#: plinth/modules/shaarli/__init__.py:18
-#, fuzzy
-#| msgid ""
-#| "When enabled, Shaarli will be available from /"
-#| "shaarli path on the web server. Note that Shaarli only supports a "
-#| "single user account, which you will need to setup on the initial visit."
msgid ""
"Note that Shaarli only supports a single user account, which you will need "
"to setup on the initial visit."
-msgstr ""
-"当启用时,Shaarli 将可从 /shaarli 路径访问。请注"
-"意,Shaarli 只支持单用户帐户,您在首次访问时安装程序。"
+msgstr "注意,Shaarli 只支持单用户帐户,您需要在初次访问时设置该帐户。"
#: plinth/modules/shaarli/__init__.py:37 plinth/modules/shaarli/manifest.py:6
msgid "Shaarli"
msgstr "Shaarli"
#: plinth/modules/shaarli/__init__.py:38
-#, fuzzy
-#| msgid ""
-#| "Bookmarks \n"
-#| " (Shaarli)"
msgid "Bookmarks"
-msgstr ""
-"书签\n"
-"(Shaarli)"
+msgstr "书签"
#: plinth/modules/shadowsocks/__init__.py:21
msgid ""
@@ -6229,10 +6049,8 @@ msgid ""
msgstr ""
#: plinth/modules/sharing/forms.py:52
-#, fuzzy
-#| msgid "This service already exists"
msgid "A share with this name already exists."
-msgstr "此服务已存在"
+msgstr "已存在同名共享。"
#: plinth/modules/sharing/forms.py:63
msgid "Shares should be either public or shared with at least one group"
@@ -6270,10 +6088,8 @@ msgid "public access"
msgstr ""
#: plinth/modules/sharing/views.py:39
-#, fuzzy
-#| msgid "Shared"
msgid "Share added."
-msgstr "共享"
+msgstr "已添加共享。"
#: plinth/modules/sharing/views.py:44
#, fuzzy
@@ -6282,10 +6098,8 @@ msgid "Add Share"
msgstr "添加服务"
#: plinth/modules/sharing/views.py:59
-#, fuzzy
-#| msgid "Shared"
msgid "Share edited."
-msgstr "共享"
+msgstr "已编辑共享。"
#: plinth/modules/sharing/views.py:64
#, fuzzy
@@ -6487,10 +6301,8 @@ msgid "Rollback to Snapshot #%(number)s"
msgstr "回滚到快照 #%(number)s"
#: plinth/modules/snapshot/views.py:27
-#, fuzzy
-#| msgid "Repository removed."
msgid "manually created"
-msgstr "储存库被移除。"
+msgstr "已手动创建"
#: plinth/modules/snapshot/views.py:28
msgid "timeline"
@@ -6625,34 +6437,29 @@ msgid "Storage"
msgstr "reStore"
#: plinth/modules/storage/__init__.py:216
-#, fuzzy, python-brace-format
-#| msgid "{disk_size} bytes"
+#, python-brace-format
msgid "{disk_size:.1f} bytes"
-msgstr "{disk_size} bytes"
+msgstr "{disk_size:.1f} 字节"
#: plinth/modules/storage/__init__.py:220
-#, fuzzy, python-brace-format
-#| msgid "{disk_size} KiB"
+#, python-brace-format
msgid "{disk_size:.1f} KiB"
-msgstr "{disk_size} KiB"
+msgstr "{disk_size:.1f} KiB"
#: plinth/modules/storage/__init__.py:224
-#, fuzzy, python-brace-format
-#| msgid "{disk_size} MiB"
+#, python-brace-format
msgid "{disk_size:.1f} MiB"
-msgstr "{disk_size} MiB"
+msgstr "{disk_size:.1f} MiB"
#: plinth/modules/storage/__init__.py:228
-#, fuzzy, python-brace-format
-#| msgid "{disk_size} GiB"
+#, python-brace-format
msgid "{disk_size:.1f} GiB"
-msgstr "{disk_size} GiB"
+msgstr "{disk_size:.1f} GiB"
#: plinth/modules/storage/__init__.py:231
-#, fuzzy, python-brace-format
-#| msgid "{disk_size} TiB"
+#, python-brace-format
msgid "{disk_size:.1f} TiB"
-msgstr "{disk_size} TiB"
+msgstr "{disk_size:.1f} TiB"
#: plinth/modules/storage/__init__.py:243
msgid "The operation failed."
@@ -6663,10 +6470,8 @@ msgid "The operation was cancelled."
msgstr ""
#: plinth/modules/storage/__init__.py:247
-#, fuzzy
-#| msgid "repro service is running"
msgid "The device is already unmounting."
-msgstr "repro 服务正在运行"
+msgstr "已经在卸载设备。"
#: plinth/modules/storage/__init__.py:249
msgid "The operation is not supported due to missing driver/tool support."
@@ -6695,16 +6500,12 @@ msgid "Not authorized to perform the requested operation."
msgstr ""
#: plinth/modules/storage/__init__.py:267
-#, fuzzy
-#| msgid "This service already exists"
msgid "The device is already mounted."
-msgstr "此服务已存在"
+msgstr "已挂载此设备。"
#: plinth/modules/storage/__init__.py:269
-#, fuzzy
-#| msgid "repro service is not running"
msgid "The device is not mounted."
-msgstr "repro 服务未运行"
+msgstr "此设备未挂载。"
#: plinth/modules/storage/__init__.py:271
msgid "Not permitted to use the requested option."
@@ -6735,20 +6536,16 @@ msgid ""
msgstr ""
#: plinth/modules/storage/forms.py:62
-#, fuzzy
-#| msgid "Invalid hostname"
msgid "Invalid directory name."
-msgstr "无效的主机名"
+msgstr "无效的目录名。"
#: plinth/modules/storage/forms.py:79
msgid "Directory does not exist."
msgstr ""
#: plinth/modules/storage/forms.py:82
-#, fuzzy
-#| msgid "Download directory"
msgid "Path is not a directory."
-msgstr "下载目录"
+msgstr "路径不是一个目录。"
#: plinth/modules/storage/forms.py:85
msgid "Directory is not readable by the user."
@@ -6876,10 +6673,8 @@ msgid ""
msgstr ""
#: plinth/modules/syncthing/__init__.py:57
-#, fuzzy
-#| msgid "Install this application?"
msgid "Administer Syncthing application"
-msgstr "安装此应用程序?"
+msgstr "管理 Syncthing 程序"
#: plinth/modules/syncthing/__init__.py:61
#: plinth/modules/syncthing/manifest.py:12
@@ -7126,9 +6921,7 @@ msgstr "网桥"
msgid ""
"If your %(box_name)s is behind a router or firewall, you should make sure "
"the following ports are open, and port-forwarded, if necessary:"
-msgstr ""
-"如果你的 %(box_name)s 是在路由器或防火墙后面,你必须确保以下端口打开,必要时"
-"打开端口转发。"
+msgstr "如果你的 %(box_name)s 在路由器或防火墙后面,你应确保以下端口处于开启状态,必要时打开端口转发:"
#: plinth/modules/tor/templates/tor.html:87
msgid "SOCKS"
@@ -7180,16 +6973,11 @@ msgstr ""
"新闻,同时提供尽可能接近真实的桌面应用程序体验。"
#: plinth/modules/ttrss/__init__.py:27
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "When enabled, Tiny Tiny RSS will be available from /"
-#| "tt-rss path on the web server."
+#, python-brace-format
msgid ""
"When enabled, Tiny Tiny RSS can be accessed by any user with a {box_name} login."
-msgstr ""
-"启用以后,Tiny Tiny RSS 将可从网页服务器的 /tt-rss 路"
-"径访问。"
+msgstr "启用后,任何 有{box_name} 登录的用户均可访问 Tiny Tiny RSS。"
#: plinth/modules/ttrss/__init__.py:31
msgid ""
@@ -7206,14 +6994,8 @@ msgid "Tiny Tiny RSS"
msgstr ""
#: plinth/modules/ttrss/__init__.py:53
-#, fuzzy
-#| msgid ""
-#| "News Feed Reader \n"
-#| " (Tiny Tiny RSS)"
msgid "News Feed Reader"
-msgstr ""
-"新闻收取阅读器\n"
-"(Tiny Tiny RSS)"
+msgstr "新闻源阅读器"
#: plinth/modules/ttrss/manifest.py:9
msgid "Tiny Tiny RSS (Fork)"
@@ -7338,13 +7120,15 @@ msgstr ""
"可以继续。"
#: plinth/modules/upgrades/templates/update-firstboot-progress.html:31
-#, fuzzy, python-format
-#| msgid "%(box_name)s Setup"
+#, python-format
msgid ""
"\n"
"\t%(box_name)s is up to date. Press Next to continue.\n"
" "
-msgstr "%(box_name)s 安装程序"
+msgstr ""
+"\n"
+"\t%(box_name)s已是最新。按“下一步”继续.\n"
+" "
#: plinth/modules/upgrades/templates/upgrades-new-release.html:9
#, fuzzy, python-format
@@ -7370,16 +7154,13 @@ msgid "Updating..."
msgstr ""
#: plinth/modules/upgrades/templates/upgrades_configure.html:32
-#, fuzzy, python-format
-#| msgid "There is a new version available."
+#, python-format
msgid "There is a new %(box_name)s version available."
-msgstr "有新版本可用"
+msgstr "有 %(box_name)s 的新版本而可用。"
#: plinth/modules/upgrades/templates/upgrades_configure.html:35
-#, fuzzy
-#| msgid "FreedomBox"
msgid "Your Freedombox needs an update!"
-msgstr "FreedomBox"
+msgstr "你的 Freedombox 需要更新!"
#: plinth/modules/upgrades/templates/upgrades_configure.html:47
msgid ""
@@ -7502,10 +7283,8 @@ msgid "Username is taken or is reserved."
msgstr "用户名已经占用或保留。"
#: plinth/modules/users/forms.py:63
-#, fuzzy
-#| msgid "Invalid server name"
msgid "Enter a valid username."
-msgstr "服务器名称无效"
+msgstr "输入有效的用户名。"
#: plinth/modules/users/forms.py:70
msgid ""
@@ -7523,19 +7302,10 @@ msgid "Enter your current password to authorize account modifications."
msgstr ""
#: plinth/modules/users/forms.py:87
-#, fuzzy
-#| msgid "Show password"
msgid "Invalid password."
-msgstr "显示密码"
+msgstr "密码无效。"
#: plinth/modules/users/forms.py:104
-#, fuzzy
-#| 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 are in the appropriate group.
Users in the admin group "
-#| "will be able to log in to all services. They can also log in to the "
-#| "system through SSH and have administrative privileges (sudo)."
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 "
@@ -7543,21 +7313,18 @@ msgid ""
"able to log in to all services. They can also log in to the system through "
"SSH and have administrative privileges (sudo)."
msgstr ""
-"选择新用户应该可以使用的服务。如果用户在适当的组中,则用户将能够通过LDAP登录"
-"支持单一登录的服务。
管理员(admin)组中的用户将能够登录所有服务。他"
-"们还可以通过 SSH 登录到系统并具有管理权限(sudo)。"
+"选择新用户应该可以使用的服务。如果用户在适当的组中,则能够通过 LDAP "
+"登录支持单点登录的服务。
管理员(admin)组中的用户将能够登录所有服务。他们还可以通过 SSH 登录到系统并具有管理权限(sudo)。"
#: plinth/modules/users/forms.py:149 plinth/modules/users/forms.py:393
-#, fuzzy, python-brace-format
-#| msgid "Creating LDAP user failed."
+#, python-brace-format
msgid "Creating LDAP user failed: {error}"
-msgstr "创建 LDAP 用户失败。"
+msgstr "创建 LDAP 用户失败:{error}"
#: plinth/modules/users/forms.py:162
-#, fuzzy, python-brace-format
-#| msgid "Failed to add new user to {group} group."
+#, python-brace-format
msgid "Failed to add new user to {group} group: {error}"
-msgstr "未能将新用户添加到 {group}。"
+msgstr "未能将新用户添加到 {group} 组:{error}"
#: plinth/modules/users/forms.py:176
msgid "Authorized SSH Keys"
@@ -7599,16 +7366,14 @@ msgid "Changing LDAP user password failed."
msgstr "更改 LDAP 用户密码失败。"
#: plinth/modules/users/forms.py:404
-#, fuzzy, python-brace-format
-#| msgid "Failed to add new user to admin group."
+#, python-brace-format
msgid "Failed to add new user to admin group: {error}"
-msgstr "未能将新用户添加到管理员组。"
+msgstr "未能将新用户添加到管理员组:{error}"
#: plinth/modules/users/forms.py:423
-#, fuzzy, python-brace-format
-#| msgid "Failed to restrict console access."
+#, python-brace-format
msgid "Failed to restrict console access: {error}"
-msgstr "限制命令行访问失败。"
+msgstr "限制控制台访问失败:{error}"
#: plinth/modules/users/forms.py:436
msgid "User account created, you are now logged in"
@@ -7664,10 +7429,8 @@ msgid "Create Account"
msgstr "创建帐户"
#: plinth/modules/users/templates/users_firstboot.html:32
-#, fuzzy
-#| msgid "Administrator Account"
msgid "An administrator account already exists."
-msgstr "管理员帐户"
+msgstr "已存在一个管理员账户。"
#: plinth/modules/users/templates/users_firstboot.html:38
msgid "The following administrator accounts exist in the system."
@@ -7709,7 +7472,7 @@ msgstr "编辑用户 %(username)s"
msgid ""
"Use the change password form to "
"change the password."
-msgstr "使用 更改密码窗口 更改密码。"
+msgstr "使用 更改密码表单 更改密码。"
#: plinth/modules/users/templates/users_update.html:31
#: plinth/templates/language-selection.html:17
@@ -7767,10 +7530,8 @@ msgid ""
msgstr ""
#: plinth/modules/wireguard/forms.py:32
-#, fuzzy
-#| msgid "Invalid kite name"
msgid "Invalid key."
-msgstr "无效的 Kite 名称"
+msgstr "无效的密钥。"
#: plinth/modules/wireguard/forms.py:61
#: plinth/modules/wireguard/templates/wireguard.html:17
@@ -7798,10 +7559,8 @@ msgid ""
msgstr ""
#: plinth/modules/wireguard/forms.py:76
-#, fuzzy
-#| msgid "Published key to keyserver."
msgid "Public key of the server"
-msgstr "已发布到密钥服务器的密钥。"
+msgstr "服务器的公钥"
#: plinth/modules/wireguard/forms.py:77
msgid ""
@@ -7898,14 +7657,8 @@ msgid "Add Allowed Client"
msgstr ""
#: plinth/modules/wireguard/templates/wireguard.html:67
-#, fuzzy
-#| msgid ""
-#| "Chat Client \n"
-#| " (JSXC)"
msgid "As a Client"
-msgstr ""
-"聊天客户端\n"
-"(JSXC)"
+msgstr "作为客户端"
#: plinth/modules/wireguard/templates/wireguard.html:69
#, python-format
@@ -7953,14 +7706,8 @@ msgid "Are you sure that you want to delete this server?"
msgstr "你确定你想移除这一项存储吗?"
#: plinth/modules/wireguard/templates/wireguard_edit_client.html:19
-#, fuzzy
-#| msgid ""
-#| "Chat Client \n"
-#| " (JSXC)"
msgid "Update Client"
-msgstr ""
-"聊天客户端\n"
-"(JSXC)"
+msgstr "更新客户端"
#: plinth/modules/wireguard/templates/wireguard_edit_server.html:19
#, fuzzy
@@ -7989,17 +7736,13 @@ msgid "Pre-shared key:"
msgstr ""
#: plinth/modules/wireguard/templates/wireguard_show_client.html:33
-#, fuzzy
-#| msgid "Server domain"
msgid "Server endpoints:"
-msgstr "服务器域"
+msgstr "服务器端点:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:41
#: plinth/modules/wireguard/templates/wireguard_show_server.html:28
-#, fuzzy
-#| msgid "Select verified SSH public key"
msgid "Server public key:"
-msgstr "选择经过验证的 SSH 公钥"
+msgstr "服务器公钥:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:53
#: plinth/modules/wireguard/templates/wireguard_show_server.html:52
@@ -8025,10 +7768,8 @@ msgid ""
msgstr ""
#: plinth/modules/wireguard/templates/wireguard_show_server.html:24
-#, fuzzy
-#| msgid "Server domain"
msgid "Server endpoint:"
-msgstr "服务器域"
+msgstr "服务器端点:"
#: plinth/modules/wireguard/templates/wireguard_show_server.html:36
msgid "Public key of this machine:"
@@ -8049,30 +7790,16 @@ msgid "Client with public key already exists"
msgstr "此服务已存在"
#: plinth/modules/wireguard/views.py:71
-#, fuzzy
-#| msgid ""
-#| "Email Client \n"
-#| " (Roundcube)"
msgid "Allowed Client"
-msgstr ""
-"邮件客户端\n"
-"(Roundcube)"
+msgstr "允许的客户端"
#: plinth/modules/wireguard/views.py:93
-#, fuzzy
-#| msgid "Update setup"
msgid "Updated client."
-msgstr "更新安装程序"
+msgstr "已更新客户端。"
#: plinth/modules/wireguard/views.py:98
-#, fuzzy
-#| msgid ""
-#| "Email Client \n"
-#| " (Roundcube)"
msgid "Modify Client"
-msgstr ""
-"邮件客户端\n"
-"(Roundcube)"
+msgstr "更改客户端"
#: plinth/modules/wireguard/views.py:131
#, fuzzy
@@ -8093,10 +7820,8 @@ msgid "Client not found"
msgstr "找不到存储库"
#: plinth/modules/wireguard/views.py:152
-#, fuzzy
-#| msgid "Added custom service"
msgid "Added new server."
-msgstr "已添加的自定义服务"
+msgstr "添加新服务器。"
#: plinth/modules/wireguard/views.py:173
#, fuzzy
@@ -8105,10 +7830,8 @@ msgid "Connection to Server"
msgstr "连接类型"
#: plinth/modules/wireguard/views.py:191
-#, fuzzy
-#| msgid "Update setup"
msgid "Updated server."
-msgstr "更新安装程序"
+msgstr "已更新服务器。"
#: plinth/modules/wireguard/views.py:196
#, fuzzy
@@ -8325,10 +8048,9 @@ msgid "Installation"
msgstr "安装"
#: plinth/templates/app.html:29
-#, fuzzy, python-format
-#| msgid "Service discovery server is not running"
+#, python-format
msgid "Service %(service_name)s is not running."
-msgstr "服务发现服务未运行"
+msgstr "服务 %(service_name)s 未在运行。"
#: plinth/templates/base.html:30
#, fuzzy, python-format
@@ -8337,30 +8059,24 @@ msgid "Core functionality and web interface for %(box_name)s"
msgstr "Plinth %(box_name)s 管理界面"
#: plinth/templates/base.html:107
-#, fuzzy
-#| msgid "Home"
msgid " Home"
-msgstr "主页"
+msgstr " 主页"
#: plinth/templates/base.html:110
msgid "Home"
msgstr "主页"
#: plinth/templates/base.html:115
-#, fuzzy
-#| msgid "Apps"
msgid " Apps"
-msgstr "应用程序"
+msgstr " 应用程序"
#: plinth/templates/base.html:119
msgid "Apps"
msgstr "应用程序"
#: plinth/templates/base.html:124
-#, fuzzy
-#| msgid "System"
msgid " System"
-msgstr "系统"
+msgstr " 系统"
#: plinth/templates/base.html:128
msgid "System"
@@ -8406,18 +8122,12 @@ msgid "Web"
msgstr ""
#: plinth/templates/clients.html:42
-#, fuzzy
-#| msgid ""
-#| "Chat Client \n"
-#| " (JSXC)"
msgid "Desktop"
-msgstr ""
-"聊天客户端\n"
-"(JSXC)"
+msgstr "桌面端"
#: plinth/templates/clients.html:53
msgid "GNU/Linux"
-msgstr ""
+msgstr "GNU/Linux"
#: plinth/templates/clients.html:55
msgid "Windows"
@@ -8428,14 +8138,8 @@ msgid "macOS"
msgstr ""
#: plinth/templates/clients.html:73
-#, fuzzy
-#| msgid ""
-#| "Email Client \n"
-#| " (Roundcube)"
msgid "Mobile"
-msgstr ""
-"邮件客户端\n"
-"(Roundcube)"
+msgstr "移动端"
#: plinth/templates/clients.html:84
msgid "Play Store"
@@ -8533,12 +8237,11 @@ msgid "Mailing list"
msgstr "邮件列表"
#: plinth/templates/internal-zone.html:11
-#, fuzzy, python-format
-#| msgid "Service discovery server is not running"
+#, python-format
msgid ""
"%(service_name)s is available only on internal networks or when the "
"client is connected to %(box_name)s through VPN."
-msgstr "服务发现服务未运行"
+msgstr "%(service_name)s仅在内网可用或仅当客户端通过 VPN 连接到 %(box_name)s 时可用。"
#: plinth/templates/internal-zone.html:17
msgid "Currently there are no network interfaces configured as internal."
@@ -8622,7 +8325,7 @@ msgstr ""
#: plinth/templates/setup.html:46
msgid "This application is currently not available in your distribution."
-msgstr "这项应用现在在你不中无法使用"
+msgstr "此应用程序目前在您的发行版中不可用。"
#: plinth/templates/setup.html:50
msgid "Check again"
From fa1986e6fa544c349489d4f51047e13fd282c0dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Podhoreck=C3=BD?=
Pokud se doménový název FreedomBox změní, veškerá data uživatelů, "
-"zaregistrovaných s předchozím názvem podu nebudou dostupná.
Diaspora* "
-"pod je dostupný na diaspora."
-"%(domain_name)s "
+"i>
Pokud se doménový název FreedomBox změní, veškerá data uživatelů, "
+"zaregistrovaných s předchozím názvem podu nebudou dostupná.
Diaspora* "
+"pod je dostupný na "
+"diaspora.%(domain_name)s "
#: plinth/modules/diaspora/templates/diaspora-pre-setup.html:36
#: plinth/modules/matrixsynapse/templates/matrix-synapse-pre-setup.html:15
@@ -1691,9 +1660,9 @@ msgid ""
"24h), it may be hard for others to find you on the Internet. This will "
"prevent others from finding services which are provided by this {box_name}."
msgstr ""
-"Pokud váš poskytovatel připojení k Internetu pravidelně mění vaší IP adresu "
-"(např. každých 24h), může pro ostatní být být těžké najít vás na Internetu. "
-"Toto ostatním zabrání nalézt služby, které jsou poskytovány tímto {box_name}."
+"Pokud váš poskytovatel internetu pravidelně mění vaši IP adresu (např. "
+"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:26
msgid ""
@@ -1776,22 +1745,17 @@ msgid "Leave this field empty if you want to keep your current password."
msgstr "Pokud chcete zachovat stávající heslo, tuto kolonku nevyplňujte."
#: plinth/modules/dynamicdns/forms.py:54
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "Optional Value. If your {box_name} is not connected directly to the "
-#| "Internet (i.e. connected to a NAT router) this URL is used to determine "
-#| "the real IP address. The URL should simply return the IP where the client "
-#| "comes from (example: http://myip.datasystems24.de)."
+#, python-brace-format
msgid ""
"Optional Value. If your {box_name} is not connected directly to the Internet "
"(i.e. connected to a NAT router) this URL is used to determine the real IP "
"address. The URL should simply return the IP where the client comes from "
"(example: https://ddns.freedombox.org/ip/)."
msgstr ""
-"Nemusí být zadáno. Pokud váš {box_name} není k Internetu připojen napřímo "
-"(tj. je připojený za NAT směrovačem) tato URL adresa slouží ke zjištění "
-"skutečné IP adresy. URL adresa by měla jen vrátit IP adresu, ze které "
-"přichází klient (příklad: http://myip.datasystems24.de)."
+"Volitelná hodnota. Pokud vaše {box_name} není připojeno přímo k internetu ("
+"tj. je připojeno ke směrovači NAT), použije se tato adresa URL k určení "
+"skutečné IP adresy. Adresa URL by měla jednoduše vrátit IP adresu, ze které "
+"klient přichází (příklad: https://ddns.freedombox.org/ip/)."
#: plinth/modules/dynamicdns/forms.py:62
msgid "The username that was used when the account was created."
@@ -1799,13 +1763,11 @@ msgstr "Uživatelské jméno které bylo použito pro vytvoření účtu."
#: plinth/modules/dynamicdns/forms.py:65
msgid "GnuDIP"
-msgstr ""
+msgstr "GnuDIP"
#: plinth/modules/dynamicdns/forms.py:68
-#, fuzzy
-#| msgid "Update URL"
msgid "other update URL"
-msgstr "URL adresa aktualizace"
+msgstr "další aktualizace URL"
#: plinth/modules/dynamicdns/forms.py:70
msgid "Enable Dynamic DNS"
@@ -1850,7 +1812,7 @@ msgstr "URL adresa na které hledat veřejnou IP adresu"
#: plinth/modules/dynamicdns/forms.py:119
msgid "Use IPv6 instead of IPv4"
-msgstr ""
+msgstr "Použijte IPv6 místo IPv4"
#: plinth/modules/dynamicdns/forms.py:141
msgid "Please provide an update URL or a GnuDIP server address"
@@ -1869,24 +1831,17 @@ msgid "Please provide a password"
msgstr "Zadejte heslo"
#: plinth/modules/dynamicdns/templates/dynamicdns.html:12
-#, fuzzy
-#| msgid ""
-#| "If you are looking for a free dynamic DNS account, you may find a free "
-#| "GnuDIP service at gnudip.datasystems24.net 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."
"freedombox.org or you may find free update URL based services at freedns.afraid.org."
msgstr ""
-"Pokud hledáte bezplatný účet dynamického DNS, můžete použít bezplatnou "
-"GnuDIP službu gnudip.datasystems24.net nebo můžete najít bezplatné na "
-"URL založené služby na "
-"freedns.afraid.org."
+"Pokud hledáte bezplatný dynamický účet DNS, můžete najít bezplatnou službu "
+"GnuDIP na adrese ddns.freedombox.org nebo můžete najít bezplatné služby založené na "
+"aktualizaci URL na adrese freedns.afraid.org."
#: plinth/modules/dynamicdns/templates/dynamicdns.html:23
#, python-format
@@ -1997,6 +1952,9 @@ msgid ""
"ejabberd needs a STUN/TURN server for audio/video calls. Install the Coturn app or configure an external server."
msgstr ""
+"Pro audio/video hovory potřebuje ejabberd server STUN/TURN. Nainstalujte "
+"aplikaci Coturn nebo nakonfigurujte externí "
+"server."
#: plinth/modules/ejabberd/__init__.py:65
msgid "ejabberd"
@@ -2026,7 +1984,7 @@ msgstr ""
#: plinth/modules/ejabberd/forms.py:27 plinth/modules/matrixsynapse/forms.py:22
msgid "Automatically manage audio/video call setup"
-msgstr ""
+msgstr "Automatická správa nastavení audio/video hovorů"
#: plinth/modules/ejabberd/forms.py:29
#, python-brace-format
@@ -2035,24 +1993,25 @@ msgid ""
"server for ejabberd. Disable this if you want to use a different STUN/TURN "
"server."
msgstr ""
+"Konfiguruje místní aplikaci coturn jako server "
+"STUN/TURN pro ejabberd. Pokud chcete používat jiný server STUN/TURN, zakažte "
+"tuto funkci."
#: plinth/modules/ejabberd/forms.py:36 plinth/modules/matrixsynapse/forms.py:31
msgid "STUN/TURN Server URIs"
-msgstr ""
+msgstr "URI serveru STUN/TURN"
#: plinth/modules/ejabberd/forms.py:38 plinth/modules/matrixsynapse/forms.py:33
msgid "List of public URIs of the STUN/TURN server, one on each line."
-msgstr ""
+msgstr "Seznam veřejných URI serveru STUN/TURN, na každém řádku jeden."
#: plinth/modules/ejabberd/forms.py:42 plinth/modules/matrixsynapse/forms.py:37
-#, fuzzy
-#| msgid "Authentication Mode"
msgid "Shared Authentication Secret"
-msgstr "Režim ověřování"
+msgstr "Sdílené ověřovací tajemství"
#: plinth/modules/ejabberd/forms.py:43 plinth/modules/matrixsynapse/forms.py:38
msgid "Shared secret used to compute passwords for the TURN server."
-msgstr ""
+msgstr "Sdílené tajemství používané k výpočtu hesel pro server TURN."
#: plinth/modules/ejabberd/manifest.py:10
msgid "Conversations"
@@ -2086,9 +2045,9 @@ msgid ""
"your own server for extra security."
msgstr ""
"ChatSecure je svobodná a open source aplikace pro komunikaci, podporující "
-"OTR šifrování přes XMPP protokol. Je možné se připojit ke stávajícímu "
-"Google účtu, vytvořit nový účet na některém z veřejných XMPP serverů (i přes "
-"Tor), nebo se dokonce připojit ještě bezpečněji, ke svému vlastnímu serveru."
+"OTR šifrování přes XMPP protokol. Je možné se připojit ke stávajícímu Google "
+"účtu, vytvořit nový účet na některém z veřejných XMPP serverů (i přes Tor), "
+"nebo se dokonce připojit ještě bezpečněji, ke svému vlastnímu serveru."
#: plinth/modules/ejabberd/manifest.py:72
msgid "Dino"
@@ -2115,110 +2074,100 @@ msgid ""
"Roundcube app provides web interface "
"for users to access email."
msgstr ""
+"Aplikace Roundcube poskytuje "
+"uživatelům webové rozhraní pro přístup k e-mailu."
#: plinth/modules/email_server/__init__.py:33
msgid ""
"During installation, any other email servers in the system will be "
"uninstalled."
msgstr ""
+"Během instalace budou odinstalovány všechny ostatní e-mailové servery v "
+"systému."
#: plinth/modules/email_server/__init__.py:44
-#, fuzzy
-#| msgid "Chat Server"
msgid "Email Server"
-msgstr "Chat server"
+msgstr "E-mailový Server"
#: plinth/modules/email_server/__init__.py:91
msgid "Powered by Postfix, Dovecot & Rspamd"
-msgstr ""
+msgstr "Běží na Postfix, Dovecot & Rspamd"
#: plinth/modules/email_server/audit/ldap.py:69
msgid "Postfix-Dovecot SASL integration"
-msgstr ""
+msgstr "Integrace Postfix-Dovecot SASL"
#: plinth/modules/email_server/audit/ldap.py:70
msgid "Postfix alias maps"
-msgstr ""
+msgstr "Mapy aliasů služby Postfix"
#: plinth/modules/email_server/audit/rcube.py:31
-#, fuzzy
-#| msgid "Available Domains"
msgid "RoundCube availability"
-msgstr "Domény k dispozici"
+msgstr "Dostupnost RoundCube"
#: plinth/modules/email_server/audit/rcube.py:32
msgid "RoundCube configured for FreedomBox email"
-msgstr ""
+msgstr "RoundCube nakonfigurovaný pro e-mailovou schránku FreedomBox"
#: plinth/modules/email_server/audit/spam.py:87
msgid "Inbound and outbound mail filters"
-msgstr ""
+msgstr "Filtry příchozí a odchozí pošty"
#: plinth/modules/email_server/audit/tls.py:81
msgid "Postfix TLS parameters"
-msgstr ""
+msgstr "Parametry Postfix TLS"
#: plinth/modules/email_server/audit/tls.py:82
msgid "Postfix uses a TLS certificate"
-msgstr ""
+msgstr "Postfix používá certifikát TLS"
#: plinth/modules/email_server/audit/tls.py:91
-#, fuzzy
-#| msgid "No certificate"
msgid "Has a TLS certificate"
-msgstr "Žádný certifikát"
+msgstr "Má certifikát TLS"
#: plinth/modules/email_server/forms.py:17
-#, fuzzy
-#| msgid "Invalid server name"
msgid "Enter a valid domain"
-msgstr "Neplatný název serveru"
+msgstr "Zadejte platnou doménu"
#: plinth/modules/email_server/forms.py:20
-#, fuzzy
-#| msgid "Invalid server name"
msgid "Enter a valid destination"
-msgstr "Neplatný název serveru"
+msgstr "Zadejte platný cíl"
#: plinth/modules/email_server/forms.py:24
-#, fuzzy
-#| msgid "Domain"
msgid "domain"
-msgstr "Doména"
+msgstr "doména"
#: plinth/modules/email_server/forms.py:38
-#, fuzzy
-#| msgid "Primary connection"
msgid "Primary domain"
-msgstr "Hlavní připojení"
+msgstr "Primární doména"
#: plinth/modules/email_server/forms.py:40
msgid ""
"Mails are received for all domains configured in the system. Among these, "
"select the most important one."
msgstr ""
+"Maily jsou přijímány pro všechny domény nakonfigurované v systému. Z nich "
+"vyberte tu nejdůležitější."
#: plinth/modules/email_server/forms.py:48
msgid "New alias (without @domain)"
-msgstr ""
+msgstr "Nový alias (bez @domain)"
#: plinth/modules/email_server/forms.py:55
msgid "Contains illegal characters"
-msgstr ""
+msgstr "Obsahuje nepovolené znaky"
#: plinth/modules/email_server/forms.py:58
msgid "Must start and end with a-z or 0-9"
-msgstr ""
+msgstr "Musí začínat a končit písmeny a-z nebo 0-9"
#: plinth/modules/email_server/forms.py:61
msgid "Cannot be a number"
-msgstr ""
+msgstr "Nemůže být číslo"
#: plinth/modules/email_server/forms.py:71
-#, fuzzy
-#| msgid "Manage Repositories"
msgid "Aliases"
-msgstr "Spravovat repozitáře"
+msgstr "Aliasy"
#: plinth/modules/email_server/forms.py:83
#: plinth/modules/firewall/templates/firewall.html:54
@@ -2242,47 +2191,37 @@ msgid "Roundcube"
msgstr "Roundcube"
#: plinth/modules/email_server/manifest.py:16
-#, fuzzy
-#| msgid "Mozilla Thunderbird"
msgid "Thunderbird"
-msgstr "Mozilla Thunderbird"
+msgstr "Thunderbird"
#: plinth/modules/email_server/manifest.py:33
msgid "K-9 Mail"
-msgstr ""
+msgstr "K-9 Mail"
#: plinth/modules/email_server/manifest.py:48
msgid "FairEmail"
-msgstr ""
+msgstr "FairEmail"
#: plinth/modules/email_server/templates/email_alias.html:13
#: plinth/modules/email_server/templates/email_server.html:20
-#, fuzzy
-#| msgid "Manage Repositories"
msgid "Manage Aliases"
-msgstr "Spravovat repozitáře"
+msgstr "Správa aliasů"
#: plinth/modules/email_server/templates/email_alias.html:16
msgid "You have no email aliases."
-msgstr ""
+msgstr "Nemáte žádné e-mailové aliasy."
#: plinth/modules/email_server/templates/email_alias.html:24
-#, fuzzy
-#| msgid "Disabled"
msgid "Disable"
-msgstr "Vypnuto"
+msgstr "Vypnout"
#: plinth/modules/email_server/templates/email_alias.html:26
-#, fuzzy
-#| msgid "Enabled"
msgid "Enable"
-msgstr "Zapnuto"
+msgstr "Zapnout"
#: plinth/modules/email_server/templates/email_alias.html:32
-#, fuzzy
-#| msgid "Create a new backup"
msgid "Create a new email alias"
-msgstr "Vytvořit novou zálohu"
+msgstr "Vytvořit nový e-mailový alias"
#: plinth/modules/email_server/templates/email_alias.html:38
#: plinth/modules/tahoe/templates/tahoe-post-setup.html:59
@@ -2290,29 +2229,25 @@ msgid "Add"
msgstr "Přidat"
#: plinth/modules/email_server/templates/email_server.html:15
-#, fuzzy
-#| msgid "Manage Snapshots"
msgid "Manage Spam"
-msgstr "Spravovat zachycené stavy"
+msgstr "Správa spamu"
#: plinth/modules/email_server/templates/email_server.html:26
-#, fuzzy
-#| msgid "Service Type"
msgid "Service Alert"
-msgstr "Typ služby"
+msgstr "Servisní upozornění"
#: plinth/modules/email_server/templates/email_server.html:46
msgid "Repair"
-msgstr ""
+msgstr "Oprava"
#: plinth/modules/email_server/views.py:73
#, python-brace-format
msgid "Internal error in {0}"
-msgstr ""
+msgstr "Vnitřní chyba v {0}"
#: plinth/modules/email_server/views.py:76
msgid "Check syslog for more information"
-msgstr ""
+msgstr "Další informace získáte v syslog"
#: plinth/modules/firewall/__init__.py:26
#, python-brace-format
@@ -2330,23 +2265,19 @@ msgid "Firewall"
msgstr "Brána firewall"
#: plinth/modules/firewall/components.py:134
-#, fuzzy, python-brace-format
-#| msgid "%(service_name)s is available only on internal networks."
+#, python-brace-format
msgid "Port {name} ({details}) available for internal networks"
-msgstr ""
-"Služba %(service_name)s je k dispozici pouze na vnitřních sítích."
+msgstr "Port {name} ({details}) dostupný pro interní sítě"
#: plinth/modules/firewall/components.py:142
-#, fuzzy, python-brace-format
-#| msgid "%(service_name)s is available only on internal networks."
+#, python-brace-format
msgid "Port {name} ({details}) available for external networks"
-msgstr ""
-"Služba %(service_name)s je k dispozici pouze na vnitřních sítích."
+msgstr "Port {name} ({details}) dostupný pro externí sítě"
#: plinth/modules/firewall/components.py:147
#, python-brace-format
msgid "Port {name} ({details}) unavailable for external networks"
-msgstr ""
+msgstr "Port {name} {details} je nedostupný pro externí sítě"
#: plinth/modules/firewall/templates/firewall.html:21
#, python-format
@@ -2396,30 +2327,30 @@ msgstr ""
#: plinth/modules/networks/templates/networks_configuration.html:22
#: plinth/modules/storage/templates/storage.html:93
msgid "Advanced"
-msgstr ""
+msgstr "Pokročilé"
#: plinth/modules/firewall/templates/firewall.html:104
msgid ""
"Advanced firewall operations such as opening custom ports are provided by "
"the Cockpit app."
msgstr ""
+"Pokročilé operace brány firewall, jako je otevírání vlastních portů, "
+"zajišťuje aplikace Cockpit."
#: plinth/modules/first_boot/forms.py:14
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "Enter the secret generated during FreedomBox installation. This secret "
-#| "can also be obtained from the file /var/lib/plinth/firstboot-wizard-secret"
+#, python-brace-format
msgid ""
"Enter the secret generated during FreedomBox installation. This secret can "
"also be obtained by running the command \"sudo cat /var/lib/plinth/firstboot-"
"wizard-secret\" on your {box_name}"
msgstr ""
-"Zadejte heslo vytvořené při instalaci FreedomBox. Toto heslo je možné získat "
-"také ze souboru /var/lib/plinth/firstboot-wizard-secret"
+"Zadejte tajemství vygenerované při instalaci FreedomBoxu. Toto tajemství lze "
+"také získat spuštěním příkazu \"sudo cat /var/lib/plinth/firstboot-wizard-"
+"secret\" na vašem {box_name}"
#: plinth/modules/first_boot/forms.py:19
msgid "Firstboot Wizard Secret"
-msgstr ""
+msgstr "Tajemství průvodce Firstboot"
#: plinth/modules/first_boot/templates/firstboot_complete.html:11
msgid "Setup Complete!"
@@ -2490,23 +2421,16 @@ msgid "Simple Git Hosting"
msgstr "Jednoduché hostování Git"
#: plinth/modules/gitweb/forms.py:59
-#, fuzzy
-#| msgid "Invalid repository name."
msgid "Invalid repository URL."
-msgstr "Neplatný název repozitáře."
+msgstr "Neplatné URL úložiště."
#: plinth/modules/gitweb/forms.py:69
msgid "Invalid repository name."
msgstr "Neplatný název repozitáře."
#: plinth/modules/gitweb/forms.py:77
-#, fuzzy
-#| msgid ""
-#| "Repository path is neither empty nor is an existing backups repository."
msgid "Name of a new repository or URL to import an existing repository."
-msgstr ""
-"Popis umístění repozitáře buď není vyplněný nebo se nejedná o existující "
-"repozitář záloh."
+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
msgid "Description of the repository"
@@ -2514,7 +2438,7 @@ msgstr "Popis repozitáře"
#: plinth/modules/gitweb/forms.py:84 plinth/modules/gitweb/forms.py:88
msgid "Optional, for displaying on Gitweb."
-msgstr "Volitelné, zobrazuje se na Gitweb"
+msgstr "Volitelné, zobrazuje se na Gitwebu."
#: plinth/modules/gitweb/forms.py:86
msgid "Repository's owner name"
@@ -2541,14 +2465,12 @@ 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
-#, fuzzy
-#| msgid "Default"
msgid "Default branch"
-msgstr "Výchozí"
+msgstr "Výchozí větev"
#: plinth/modules/gitweb/forms.py:135
msgid "Gitweb displays this as a default branch."
-msgstr ""
+msgstr "Gitweb ji zobrazí jako výchozí větev."
#: plinth/modules/gitweb/manifest.py:18
msgid "Git"
@@ -2574,7 +2496,7 @@ msgstr "Přejít do repozitáře %(repo.name)s"
#: plinth/modules/gitweb/templates/gitweb_configure.html:42
msgid "Cloning…"
-msgstr ""
+msgstr "Klonování…"
#: plinth/modules/gitweb/templates/gitweb_configure.html:59
#, python-format
@@ -2595,10 +2517,8 @@ msgid "Repository created."
msgstr "Repozitář vytvořen."
#: plinth/modules/gitweb/views.py:69
-#, fuzzy
-#| msgid "An error occurred during configuration."
msgid "An error occurred while creating the repository."
-msgstr "Při nastavování se vyskytla chyba."
+msgstr "Při vytváření úložiště došlo k chybě."
#: plinth/modules/gitweb/views.py:84
msgid "Repository edited."
@@ -2614,8 +2534,6 @@ msgstr "Dokumentace"
#: plinth/modules/help/__init__.py:36 plinth/templates/help-menu.html:20
#: plinth/templates/help-menu.html:21 plinth/templates/index.html:128
-#, fuzzy
-#| msgid "Manual"
msgctxt "User guide"
msgid "Manual"
msgstr "Příručka"
@@ -2648,12 +2566,12 @@ msgid "You are running %(os_release)s and %(box_name)s version %(version)s."
msgstr "Provozujete %(os_release)s a %(box_name)s verze %(version)s."
#: plinth/modules/help/templates/help_about.html:23
-#, fuzzy, python-format
-#| msgid "There is a new %(box_name)s version available."
+#, python-format
msgid ""
"There is a new %(box_name)s version available"
"a>."
-msgstr "Je k dispozici nová verze %(box_name)s."
+msgstr ""
+"Je tu nová verze %(box_name)s k dispozici."
#: plinth/modules/help/templates/help_about.html:28
#: plinth/modules/upgrades/templates/upgrades_configure.html:37
@@ -2717,10 +2635,8 @@ msgstr ""
"debian.org/FreedomBox\">%(box_name)s Wiki."
#: plinth/modules/help/templates/help_about.html:78
-#, fuzzy
-#| msgid "Learn more..."
msgid "Learn more"
-msgstr "Zjistit více…"
+msgstr "Více informací"
#: plinth/modules/help/templates/help_base.html:21
#: plinth/modules/help/templates/help_index.html:61
@@ -2757,6 +2673,13 @@ msgid ""
"throughout the world. The FreedomBox Foundation would not exist without its "
"supporters."
msgstr ""
+"Projektu můžete také finančně pomoci přispěním neziskové nadaci FreedomBox Foundation. Nadace "
+"FreedomBox byla založena v roce 2011 a je neziskovou organizací se statutem "
+"501(c)(3) se sídlem v New Yorku, která existuje za účelem podpory "
+"FreedomBoxu. Zajišťuje technickou infrastrukturu a právní služby pro "
+"projekt, usiluje o partnerství a prosazuje FreedomBox po celém světě. Nadace "
+"FreedomBox by neexistovala bez svých podporovatelů."
#: plinth/modules/help/templates/help_contribute.html:42
#: plinth/modules/power/templates/power_restart.html:27
@@ -2781,23 +2704,17 @@ msgstr ""
"target=\"_blank\"> diskuzním fóru."
#: plinth/modules/help/templates/help_feedback.html:26
-#, fuzzy
-#| msgid ""
-#| "If you find any bugs or issues, please use the issue "
-#| "tracker to let our developers know. To report, first check if the "
-#| "issue is already reported and then use the \"New issue\" button."
msgid ""
"If you find any bugs or issues, please use the issue "
"tracker to let our developers know. To report, first check if the issue "
"is already reported and then use the \"New issue\" button."
msgstr ""
-"Pokud naleznete chybu nebo problém, dejte o tom vědět vývojářům "
-"prostřednictvím systému pro správu hlášení problémů. Pro "
-"nahlášení, nejprve zkontrolujte, zda problém už nebyl nahlášen někým jiným a "
-"pak použijte tlačítko „Nový problém“."
+"Pokud najdete nějaké chyby nebo problémy, použijte prosím sledovač problémů a dejte vědět našim vývojářům. Chcete-li problém "
+"nahlásit, nejprve zkontrolujte, zda již nebyl nahlášen, a poté použijte "
+"tlačítko \"Nový problém\"."
#: plinth/modules/help/templates/help_feedback.html:36
msgid "Thank you!"
@@ -2863,7 +2780,7 @@ msgid ""
"using %(box_name)s, you can ask for help from our community of users and "
"contributors."
msgstr ""
-"Pokud potřebujete s něčím poradit nebo se potýkáte s problémy při používání "
+"Pokud potřebujete s něčím poradit nebo se potýkáte s problémy při používání "
"%(box_name)s, můžete se obrátit na naši komunitu uživatelů a přispěvatelů."
#: plinth/modules/help/templates/help_support.html:20
@@ -2881,28 +2798,27 @@ msgid ""
"Or send an email to our mailing list."
msgstr ""
+"Můžete s námi také chatovat na našich kanálech IRC a Matrix (přemostěných): "
+"
Vašeho {box_name} získává " +"připojení k internetu ze směrovače prostřednictvím Wi-Fi nebo ethernetového " +"kabelu. Jedná se o typické domácí nastavení.
" #: plinth/modules/networks/forms.py:324 #, python-brace-format @@ -4318,6 +4242,10 @@ msgid "" "adapter. {box_name} is directly connected to the Internet and all your " "devices connect to {box_name} for their Internet connectivity." msgstr "" +"{box_name} je váš routerVáš {box_name} má několik " +"síťových rozhraní, jako je několik ethernetových portů nebo adaptér Wi-Fi. " +"Zařízení {box_name} je přímo připojeno k internetu a všechna vaše zařízení " +"se připojují k zařízení {box_name}, aby se mohli připojit k internetu.
" #: plinth/modules/networks/forms.py:333 #, python-brace-format @@ -4326,10 +4254,13 @@ msgid "" "connection is directly attached to your {box_name} and there are no other " "devices on the network. This can happen on community or cloud setups." msgstr "" +"Přímo připojeno k internetuVaše připojení k " +"internetu je přímo připojeno k vašemu {box_name} a v síti nejsou žádná další " +"zařízení. To se může stát u komunitních nebo cloudových nastavení.
" #: plinth/modules/networks/forms.py:352 msgid "Choose your internet connection type" -msgstr "" +msgstr "Zvolte typ internetového připojení" #: plinth/modules/networks/forms.py:356 msgid "" @@ -4341,6 +4272,14 @@ msgid "" "connectivity. If you have a public IP address but are unsure if it changes " "over time or not, it is safer to choose this option." msgstr "" +"Mám veřejnou IP adresu, která se může v průběhu času měnitTo znamená, že zařízení na internetu vás mohou dosáhnout, když jste " +"připojeni k internetu. Pokaždé, když se připojíte k internetu u svého " +"poskytovatele internetových služeb (ISP), můžete získat jinou IP adresu, " +"zejména po určité době offline. Tento typ připojení nabízí mnoho " +"poskytovatelů internetových služeb. Pokud máte veřejnou IP adresu, ale " +"nejste si jisti, zda se v průběhu času mění nebo ne, je bezpečnější zvolit " +"tuto možnost.
" #: plinth/modules/networks/forms.py:368 #, python-brace-format @@ -4353,6 +4292,13 @@ msgid "" "but very few ISPs offer this. You may be able to get this service from your " "ISP by making an additional payment." msgstr "" +"Mám veřejnou IP adresu, která se v průběhu času nemění (doporučeno)To znamená, že zařízení na internetu vás mohou dosáhnout, " +"když jste připojeni k internetu. Pokaždé, když se připojíte k internetu u " +"svého poskytovatele internetových služeb (ISP), dostanete vždy stejnou IP " +"adresu. Jedná se o nejbezproblémovější nastavení mnoha {box_name} služeb, " +"které však nabízí jen velmi málo poskytovatelů internetových služeb. Tuto " +"službu můžete od svého poskytovatele internetu získat za příplatek.
" #: plinth/modules/networks/forms.py:381 #, python-brace-format @@ -4365,18 +4311,26 @@ msgid "" "troublesome situation for hosting services at home. {box_name} provides many " "workaround solutions but each solution has some limitations." msgstr "" +"Nemám veřejnou IP adresuTo znamená, že zařízení na " +"internetu se k vám nemohou dostat, když jste připojeni k internetu. " +"Pokaždé, když se připojíte k internetu prostřednictvím poskytovatele " +"internetových služeb (ISP), získáte IP adresu, která je relevantní pouze pro " +"místní sítě. Tento typ připojení nabízí mnoho poskytovatelů internetových " +"služeb. Tato situace je pro domácí hostingové služby nejproblematičtější. " +"{box_name} nabízí mnoho řešení, jak tuto situaci obejít, ale každé řešení má " +"určitá omezení.
" #: plinth/modules/networks/forms.py:394 msgid "" "I do not know the type of connection my ISP providesYou will be suggested the most conservative actions.
" msgstr "" +"Nevím, jaký typ připojení můj poskytovatel internetu poskytujeBudou vám navrženy nejkonzervativnější kroky.
" #: plinth/modules/networks/forms.py:411 -#, fuzzy -#| msgid "Current Network Configuration" msgid "Preferred router configuration" -msgstr "Stávající nastavení sítě" +msgstr "Upřednostňovaná konfigurace směrovače" #: plinth/modules/networks/forms.py:416 #, python-brace-format @@ -4388,6 +4342,12 @@ msgid "" "static local IP address for your {box_name} in your router's configuration." "p>" msgstr "" +"Použijte funkci DMZ k přesměrování veškerého provozu (doporučeno)Většina směrovačů poskytuje konfigurační nastavení zvané " +"DMZ. To routeru umožní přesměrovat veškerý příchozí provoz z internetu na " +"jedinou IP adresu, jako je IP adresa {box_name}. Nejprve nezapomeňte v " +"konfiguraci routeru nakonfigurovat statickou místní IP adresu pro váš " +"{box_name}.
" #: plinth/modules/networks/forms.py:428 #, python-brace-format @@ -4400,6 +4360,13 @@ msgid "" "443 to work. Each of the other applications will suggest which port(s) need " "to be forwarded for that application to work." msgstr "" +"Přesměrování specifického provozu podle potřeby jednotlivých aplikacíMůžete také zvolit přesměrování pouze specifického " +"provozu do vašeho {box_name}. To je ideální, pokud máte v síti další servery " +"jako {box_name} nebo pokud váš směrovač nepodporuje funkci DMZ. Všechny " +"aplikace, které poskytují webové rozhraní, potřebují ke svému fungování " +"přesměrování provozu z portů 80 a 443. Každá z ostatních aplikací vám " +"nabídne, které porty je třeba přesměrovat, aby daná aplikace fungovala.
" #: plinth/modules/networks/forms.py:442 msgid "" @@ -4407,6 +4374,10 @@ msgid "" "have not configured or are unable to configure the router currently and wish " "to be reminded later. Some of the other configuration steps may fail." msgstr "" +"Router je aktuálně nenakonfigurovánZvolte tuto " +"možnost, pokud jste router nenakonfigurovali nebo jej aktuálně nemůžete " +"nakonfigurovat a přejete si být připomenuti později. Některé další " +"konfigurační kroky mohou selhat.
" #: plinth/modules/networks/templates/connection_show.html:24 #, python-format @@ -4694,20 +4665,22 @@ msgstr "Vytvořit…" #: plinth/modules/networks/templates/internet_connectivity_content.html:10 msgid "What Type Of Internet Connection Do You Have?" -msgstr "" +msgstr "Jaký typ připojení k internetu máte?" #: plinth/modules/networks/templates/internet_connectivity_content.html:16 msgid "" "Select an option that best describes the type of Internet connection. This " "information is used only to guide you with further setup." msgstr "" +"Vyberte možnost, která nejlépe vystihuje typ připojení k Internetu. Tyto " +"informace slouží pouze jako vodítko pro další nastavení." #: plinth/modules/networks/templates/internet_connectivity_firstboot.html:19 #: plinth/modules/networks/templates/network_topology_firstboot.html:19 #: plinth/modules/networks/templates/router_configuration_firstboot.html:19 #: plinth/modules/users/templates/users_firstboot.html:63 msgid "Skip this step" -msgstr "" +msgstr "Tento krok přeskočte" #: plinth/modules/networks/templates/internet_connectivity_firstboot.html:21 #: plinth/modules/networks/templates/network_topology_firstboot.html:21 @@ -4717,7 +4690,7 @@ msgstr "" #: plinth/modules/upgrades/templates/update-firstboot-progress.html:38 #: plinth/modules/upgrades/templates/update-firstboot.html:33 msgid "Next" -msgstr "" +msgstr "Další" #: plinth/modules/networks/templates/internet_connectivity_main.html:9 #, fuzzy @@ -4731,35 +4704,40 @@ msgid "" "your ISP. This information is only used to suggest you necessary " "configuration actions." msgstr "" +"Typ internetového připojení poskytovaného vaším poskytovatelem internetových " +"služeb nejlépe vystihuje následující popis. Tyto informace slouží pouze k " +"tomu, abyste mohli navrhnout potřebné konfigurační akce." #: plinth/modules/networks/templates/internet_connectivity_main.html:23 msgid "My ISP provides a public IP address that does not change over time." msgstr "" +"Můj poskytovatel internetu poskytuje veřejnou IP adresu, která se v průběhu " +"času nemění." #: plinth/modules/networks/templates/internet_connectivity_main.html:27 msgid "My ISP provides a public IP address that may change over time." msgstr "" +"Můj poskytovatel internetu poskytuje veřejnou IP adresu, která se může v " +"průběhu času měnit." #: plinth/modules/networks/templates/internet_connectivity_main.html:31 msgid "My ISP does not provide a public IP address." -msgstr "" +msgstr "Můj poskytovatel internetu neposkytuje veřejnou IP adresu." #: plinth/modules/networks/templates/internet_connectivity_main.html:35 msgid "I do not know the type of connection my ISP provides." msgstr "" +"Nevím, jaký typ připojení můj poskytovatel internetového připojení poskytuje." #: plinth/modules/networks/templates/internet_connectivity_main.html:41 #: plinth/modules/networks/templates/network_topology_main.html:41 -#, fuzzy -#| msgid "Update" msgid "Update..." -msgstr "Aktualizovat" +msgstr "Aktualizovat..." #: plinth/modules/networks/templates/network_topology_content.html:10 -#, fuzzy, python-format -#| msgid "Direct connection to the Internet." +#, python-format msgid "How is Your %(box_name)s Connected to the Internet?" -msgstr "Přímé připojení do Internetu." +msgstr "Jak je váš %(box_name)s připojen k internetu?" #: plinth/modules/networks/templates/network_topology_content.html:16 #, python-format @@ -4808,12 +4786,13 @@ msgid "" "Advanced networking operations such as bonding, bridging and VLAN management " "are provided by the Cockpit app." msgstr "" +"Pokročilé síťové operace, jako je spojování, přemostění a správa VLAN, " +"zajišťuje aplikace Cockpit." #: plinth/modules/networks/templates/router_configuration_content.html:10 -#, fuzzy, python-format -#| msgid "%(box_name)s is up to date." +#, python-format msgid "Setup %(box_name)s Behind a Router" -msgstr "%(box_name)s je aktuální." +msgstr "Nastavení %(box_name)s za směrovačem" #: plinth/modules/networks/templates/router_configuration_content.html:16 #, python-format @@ -4837,16 +4816,21 @@ msgid "" "see options to overcome this limitation, choose 'no public address' option " "in Internet connection type selection." msgstr "" +"Pokud nemáte kontrolu nad směrovačem, rozhodněte se jej nenastavovat. Chcete-" +"li zobrazit možnosti, jak toto omezení překonat, zvolte ve výběru typu " +"připojení k internetu možnost \"bez veřejné adresy\"." #: plinth/modules/networks/templates/router_configuration_content.html:39 msgid "Choose How You Wish to Configure Your Router" -msgstr "" +msgstr "Zvolte, jak chcete směrovač nakonfigurovat" #: plinth/modules/networks/templates/router_configuration_content.html:42 msgid "" "You will need to login to your router's administration console provided by " "the router. This may look like one of the following:" msgstr "" +"Musíte se přihlásit do konzoly pro správu směrovače, kterou poskytuje " +"směrovač. Ta může vypadat následovně:" #: plinth/modules/networks/templates/router_configuration_content.html:54 msgid "" @@ -4857,6 +4841,12 @@ msgid "" "model number and search online for the router's manual. This will provide " "full instructions on how to perform this task." msgstr "" +"Uživatelské jméno a heslo nastavíte při prvním nastavení směrovače. U mnoha " +"směrovačů jsou tyto informace vytištěny na zadní straně směrovače. Pokud si " +"přihlašovací údaje nebo IP adresu směrovače nepamatujete, můžete se " +"rozhodnout je resetovat a nastavit je nově. Vyhledejte číslo modelu " +"směrovače a vyhledejte na internetu jeho příručku. Ten vám poskytne úplné " +"pokyny k provedení tohoto úkolu." #: plinth/modules/networks/views.py:27 #, fuzzy @@ -4884,12 +4874,12 @@ msgstr "Sdílené" #: plinth/modules/networks/views.py:31 msgid "link-local" -msgstr "" +msgstr "link-local" #: plinth/modules/networks/views.py:37 plinth/modules/networks/views.py:98 #: plinth/modules/networks/views.py:109 msgid "unknown" -msgstr "" +msgstr "neznámý" #: plinth/modules/networks/views.py:38 #, fuzzy @@ -4929,15 +4919,15 @@ msgstr "Použít základní HTTP ověřování" #: plinth/modules/networks/views.py:44 msgid "requesting address" -msgstr "" +msgstr "vyžadující adresu" #: plinth/modules/networks/views.py:45 msgid "checking" -msgstr "" +msgstr "kontrola" #: plinth/modules/networks/views.py:46 msgid "waiting for secondary" -msgstr "" +msgstr "čekání na sekundární" #: plinth/modules/networks/views.py:47 #, fuzzy @@ -4959,19 +4949,15 @@ msgstr "Důvod stavu" #: plinth/modules/networks/views.py:58 msgid "unknown error" -msgstr "" +msgstr "neznámá chyba" #: plinth/modules/networks/views.py:60 -#, fuzzy -#| msgid "The device is not mounted." msgid "device is now managed" -msgstr "Zařízení není připojeno." +msgstr "zařízení je nyní spravováno" #: plinth/modules/networks/views.py:62 -#, fuzzy -#| msgid "The device is not mounted." msgid "device is now unmanaged" -msgstr "Zařízení není připojeno." +msgstr "zařízení je nyní bez správy" #: plinth/modules/networks/views.py:64 #, fuzzy @@ -4992,32 +4978,24 @@ msgid "DHCP client error" msgstr "" #: plinth/modules/networks/views.py:72 -#, fuzzy -#| msgid "Archive deleted." msgid "DHCP client failed" -msgstr "Archiv smazán." +msgstr "Klient DHCP selhal" #: plinth/modules/networks/views.py:74 msgid "shared connection service failed to start" msgstr "" #: plinth/modules/networks/views.py:76 -#, fuzzy -#| msgid "The operation failed." msgid "shared connection service failed" -msgstr "Operace se nezdařila." +msgstr "služba sdíleného připojení selhala" #: plinth/modules/networks/views.py:78 -#, fuzzy -#| msgid "The device is already mounted." msgid "device was removed" -msgstr "Toto zařízení je už připojeno (mount)." +msgstr "zařízení bylo odstraněno" #: plinth/modules/networks/views.py:80 -#, fuzzy -#| msgid "The device is mounted by another user." msgid "device disconnected by user" -msgstr "Zařízení je připojeno jiným uživatelem." +msgstr "zařízení odpojené uživatelem" #: plinth/modules/networks/views.py:82 msgid "a dependency of the connection failed" @@ -5030,10 +5008,8 @@ msgid "Wi-Fi network not found" msgstr "Repozitář nenalezen" #: plinth/modules/networks/views.py:86 -#, fuzzy -#| msgid "The operation failed." msgid "a secondary connection failed" -msgstr "Operace se nezdařila." +msgstr "selhalo sekundární připojení" #: plinth/modules/networks/views.py:88 msgid "new connection activation was enqueued" @@ -5278,9 +5254,10 @@ msgid "" "services are unreachable from the rest of the Internet. This includes the " "following situations:" msgstr "" -"PageKite je systém pro vystavení služeb {box_name} na Internet, i když k " -"němu nejste připojení napřímo. Potřebujete ho pouze když jsou služby služby " -"vašeho {box_name} nedostupné z Internetu. To zahrnuje následující situace:" +"PageKite je systém pro vystavení služeb {box_name}, pokud nemáte přímé " +"připojení k Internetu. Potřebujete jej pouze v případě, že vaše služby " +"{box_name} nejsou dostupné ze zbytku internetu. To zahrnuje následující " +"situace:" #: plinth/modules/pagekite/__init__.py:26 #, python-brace-format @@ -5387,7 +5364,7 @@ msgid "" "A secret associated with the kite or the default secret for your account if " "no secret is set on the kite." msgstr "" -"Heslo přiřazené ke kite nebo výchozí heslo pro váš účet pokud není na kite " +"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 @@ -5955,10 +5932,8 @@ msgid "" msgstr "" #: plinth/modules/samba/templates/samba.html:140 -#, fuzzy -#| msgid "Share added." msgid "Share name" -msgstr "Sdílení přidáno." +msgstr "Sdílet název" #: plinth/modules/samba/templates/samba.html:141 #, fuzzy @@ -6348,10 +6323,8 @@ 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 -#, fuzzy -#| msgid "User groups who can read the files in the share" msgid "User groups that can read the files in the share:" -msgstr "Skupina uživatelů která může číst soubory na sdílení" +msgstr "Skupina uživatelů která může číst soubory na sdílení:" #: plinth/modules/sharing/forms.py:36 #, fuzzy @@ -6613,10 +6586,8 @@ msgid "Rollback to Snapshot #%(number)s" msgstr "Vrátit k zachycenému stavu č. %(number)s" #: plinth/modules/snapshot/views.py:27 -#, fuzzy -#| msgid "Repository created." msgid "manually created" -msgstr "Repozitář vytvořen." +msgstr "ručně vytvořen" #: plinth/modules/snapshot/views.py:28 msgid "timeline" @@ -6860,10 +6831,8 @@ msgid "Directory does not exist." msgstr "" #: plinth/modules/storage/forms.py:82 -#, fuzzy -#| msgid "Download directory" msgid "Path is not a directory." -msgstr "Složka pro stahování" +msgstr "Cesta není adresář." #: plinth/modules/storage/forms.py:85 #, fuzzy @@ -7138,7 +7107,7 @@ msgstr "Přistoupit k URL adrese {url} na tcp{kind} prostřednictvím Tor" #: plinth/modules/tor/__init__.py:217 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" -msgstr "Potvrdit použití Tor na {url} na tcp{kind}" +msgstr "Potvrďte použití Tor na adrese {url} na tcp{kind}" #: plinth/modules/tor/forms.py:33 msgid "" @@ -7495,19 +7464,20 @@ msgstr "" "dočasně nedostupné a zobrazovat chybu. V takovém případě ho načtěte znovu." #: plinth/modules/upgrades/templates/update-firstboot-progress.html:31 -#, fuzzy, python-format -#| msgid "%(box_name)s is up to date." +#, python-format msgid "" "\n" "\t%(box_name)s is up to date. Press Next to continue.\n" " " -msgstr "%(box_name)s je aktuální." +msgstr "" +"\n" +"\t%(box_name)s je aktuální. Stiskněte tlačítko Další a pokračujte.\n" +" " #: plinth/modules/upgrades/templates/upgrades-new-release.html:9 -#, fuzzy, python-format -#| msgid "%(box_name)s is up to date." +#, python-format msgid "%(box_name)s Updated" -msgstr "%(box_name)s je aktuální." +msgstr "%(box_name)s aktualizován" #: plinth/modules/upgrades/templates/upgrades-new-release.html:13 #, python-format @@ -7532,10 +7502,8 @@ msgid "There is a new %(box_name)s version available." msgstr "Je k dispozici nová verze %(box_name)s." #: plinth/modules/upgrades/templates/upgrades_configure.html:35 -#, fuzzy -#| msgid "FreedomBox Foundation" msgid "Your Freedombox needs an update!" -msgstr "Nadace FreedomBox" +msgstr "Váš Freedombox potřebuje aktualizaci!" #: plinth/modules/upgrades/templates/upgrades_configure.html:47 msgid "" @@ -7658,10 +7626,8 @@ msgstr "" "Toto uživatelské jméno je už používáno někým jiným nebo vyhrazeno pro systém." #: plinth/modules/users/forms.py:63 -#, fuzzy -#| msgid "Invalid server name" msgid "Enter a valid username." -msgstr "Neplatný název serveru" +msgstr "Zadejte platné uživatelské jméno." #: plinth/modules/users/forms.py:70 msgid "" @@ -7679,10 +7645,8 @@ msgid "Enter your current password to authorize account modifications." msgstr "" #: plinth/modules/users/forms.py:87 -#, fuzzy -#| msgid "Show password" msgid "Invalid password." -msgstr "Zobrazit heslo" +msgstr "Neplatné heslo." #: plinth/modules/users/forms.py:104 #, fuzzy @@ -7706,10 +7670,9 @@ msgstr "" "přihlásit také prostřednictvím SSH a mají práva správy (sudo)." #: plinth/modules/users/forms.py:149 plinth/modules/users/forms.py:393 -#, fuzzy, python-brace-format -#| msgid "Creating LDAP user failed." +#, python-brace-format msgid "Creating LDAP user failed: {error}" -msgstr "Vytvoření LDAP uživatele se nezdařilo." +msgstr "Vytvoření uživatele LDAP se nezdařilo: {error}" #: plinth/modules/users/forms.py:162 #, fuzzy, python-brace-format @@ -8151,17 +8114,13 @@ msgid "Pre-shared key:" msgstr "" #: plinth/modules/wireguard/templates/wireguard_show_client.html:33 -#, fuzzy -#| msgid "Server domain" msgid "Server endpoints:" -msgstr "Doména serveru" +msgstr "Koncové body serveru:" #: plinth/modules/wireguard/templates/wireguard_show_client.html:41 #: plinth/modules/wireguard/templates/wireguard_show_server.html:28 -#, fuzzy -#| msgid "Select verified SSH public key" msgid "Server public key:" -msgstr "Vyberte ověřený SSH veřejný klíč" +msgstr "Veřejný klíč serveru:" #: plinth/modules/wireguard/templates/wireguard_show_client.html:53 #: plinth/modules/wireguard/templates/wireguard_show_server.html:52 @@ -8187,10 +8146,8 @@ msgid "" msgstr "" #: plinth/modules/wireguard/templates/wireguard_show_server.html:24 -#, fuzzy -#| msgid "Server domain" msgid "Server endpoint:" -msgstr "Doména serveru" +msgstr "Koncový bod serveru:" #: plinth/modules/wireguard/templates/wireguard_show_server.html:36 msgid "Public key of this machine:" From 697653ac865173caa4dad8a01d52a20776b9abf9 Mon Sep 17 00:00:00 2001 From: pesderimap.example.com. For IMAP over SSL (recommended), "
-#| "fill the server field like imaps://imap.example.com."
msgid ""
"You can use it by providing the username and password of the email account "
"you wish to access followed by the domain name of the IMAP server for your "
@@ -5790,11 +5738,11 @@ msgid ""
"(recommended), fill the server field like imaps://imap.example.com"
"code>."
msgstr ""
-"K Roundcube je možné pristupovat z /roundcube. "
-"Zadejte uživatelské jméno a heslo e-mailového účtu ke kterému si přejete "
-"přistoupit, následovaném názvem domény IMAP serveru vašeho poskytovatele e-"
-"mailu, jako imap.example.com. Pro IMAP přes SSL (doporučeno), "
-"vyplňte kolonku server jakoimaps://imap.example.com."
+"Můžete ji použít zadáním uživatelského jména a hesla e-mailového účtu, ke "
+"kterému chcete získat přístup, a následně názvu domény serveru IMAP vašeho "
+"poskytovatele e-mailu, například imap.example.com. V případě "
+"protokolu IMAP přes SSL (doporučeno) vyplňte pole serveru například "
+"imaps://imap.example.com."
#: plinth/modules/roundcube/__init__.py:30
msgid ""
@@ -5821,6 +5769,8 @@ msgid ""
"Samba allows to share files and folders between FreedomBox and other "
"computers in your local network."
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
#, python-brace-format
@@ -5830,64 +5780,64 @@ msgid ""
"\\{hostname} (on Windows) or smb://{hostname}.local (on Linux and Mac). "
"There are three types of shares you can choose from: "
msgstr ""
+"Po instalaci si můžete vybrat disky, které chcete použít ke sdílení. "
+"Povolená sdílení jsou přístupná ve správci souborů v počítači v umístění \\\\"
+"{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
msgid "Open share - accessible to everyone in your local network."
-msgstr ""
+msgstr "Otevřené sdílení - přístupné všem v místní síti."
#: plinth/modules/samba/__init__.py:36
msgid ""
"Group share - accessible only to FreedomBox users who are in the freedombox-"
"share group."
msgstr ""
+"Sdílení ve skupině - přístupné pouze uživatelům FreedomBoxu, kteří jsou ve "
+"skupině freedombox-share."
#: plinth/modules/samba/__init__.py:38
msgid ""
"Home share - every user in the freedombox-share group can have their own "
"private space."
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:56
msgid "Access to the private shares"
-msgstr ""
+msgstr "Přístup k soukromému sdílení"
#: plinth/modules/samba/__init__.py:59
msgid "Samba"
-msgstr ""
+msgstr "Samba"
#: plinth/modules/samba/__init__.py:60
-#, fuzzy
-#| msgid "Distributed File Storage"
msgid "Network File Storage"
msgstr "Distribuované souborové úložiště"
#: plinth/modules/samba/manifest.py:14
-#, fuzzy
-#| msgid "IRC Client"
msgid "Android Samba Client"
-msgstr "IRC klient"
+msgstr "Android Samba Client"
#: plinth/modules/samba/manifest.py:27
msgid "Ghost Commander - Samba plugin"
-msgstr ""
+msgstr "Ghost Commander - Samba plugin"
#: plinth/modules/samba/manifest.py:41
msgid "VLC media player"
-msgstr ""
+msgstr "VLC media player"
#: plinth/modules/samba/manifest.py:55
-#, fuzzy
-#| msgid "GNOME Calendar"
msgid "GNOME Files"
-msgstr "Kalendář GNOME"
+msgstr "GNOME soubory"
#: plinth/modules/samba/manifest.py:67
msgid "Dolphin"
-msgstr ""
+msgstr "Dolphin"
#: plinth/modules/samba/templates/samba.html:20
-#, fuzzy
-#| msgid "Shared"
msgid "Shares"
msgstr "Sdílené"
@@ -5896,10 +5846,12 @@ msgid ""
"Note: Only specially created directories will be shared on selected disks, "
"not the whole disk."
msgstr ""
+"Poznámka: Na vybraných discích budou sdíleny pouze speciálně vytvořené "
+"adresáře, nikoli celý disk."
#: plinth/modules/samba/templates/samba.html:84
msgid "VFAT partitions are not supported"
-msgstr ""
+msgstr "Oddíly VFAT nejsou podporovány"
#: plinth/modules/samba/templates/samba.html:112
#, python-format
@@ -5908,86 +5860,77 @@ msgid ""
"\"%(storage_url)s\">storage module page and configure access to the "
"shares on the users module page."
msgstr ""
+"Další informace o discích najdete na stránce modulu storage a přístup ke sdíleným položkám nakonfigurujete na stránce "
+"modulu users."
#: plinth/modules/samba/templates/samba.html:120
msgid "Users who can currently access group and home shares"
msgstr ""
+"Uživatelé, kteří mají aktuálně přístup ke skupinovým a domácím sdíleným "
+"položkám"
#: plinth/modules/samba/templates/samba.html:124
msgid ""
"Users needing to re-enter their password on the password change page to "
"access group and home shares"
msgstr ""
+"Uživatelé musí na stránce pro změnu hesla znovu zadávat své heslo pro "
+"přístup ke skupinovým a domovským sdílením"
#: plinth/modules/samba/templates/samba.html:129
-#, fuzzy
-#| msgid "Available Domains"
msgid "Unavailable Shares"
-msgstr "Domény k dispozici"
+msgstr "Nedostupná sdílení"
#: plinth/modules/samba/templates/samba.html:131
msgid ""
"Shares that are configured but the disk is not available. If the disk is "
"plugged back in, sharing will be automatically enabled."
msgstr ""
+"Sdílené složky, které jsou nakonfigurovány, ale disk není k dispozici. Pokud "
+"je disk znovu připojen, sdílení se automaticky povolí."
#: plinth/modules/samba/templates/samba.html:140
msgid "Share name"
msgstr "Sdílet název"
#: plinth/modules/samba/templates/samba.html:141
-#, fuzzy
-#| msgid "Actions"
msgid "Action"
msgstr "Akce"
#: plinth/modules/samba/views.py:33
-#, fuzzy
-#| msgid "FreedomBox"
msgid "FreedomBox OS disk"
-msgstr "FreedomBox"
+msgstr "FreedomBox OS disk"
#: plinth/modules/samba/views.py:59 plinth/modules/storage/forms.py:146
-#, fuzzy
-#| msgid "Add Share"
msgid "Open Share"
-msgstr "Přidat sdílení"
+msgstr "Otevřít sdílení"
#: plinth/modules/samba/views.py:63 plinth/modules/storage/forms.py:144
-#, fuzzy
-#| msgid "Add Share"
msgid "Group Share"
-msgstr "Přidat sdílení"
+msgstr "Skupinové sdílení"
#: plinth/modules/samba/views.py:67
-#, fuzzy
-#| msgid "Homepage"
msgid "Home Share"
-msgstr "Domovská stránka"
+msgstr "Domácí sdílení"
#: plinth/modules/samba/views.py:102
-#, fuzzy
-#| msgid "Share deleted."
msgid "Share enabled."
-msgstr "Sdílení smazáno."
+msgstr "Sdílení povoleno."
#: plinth/modules/samba/views.py:107
-#, fuzzy, python-brace-format
-#| msgid "Error ejecting device: {error_message}"
+#, python-brace-format
msgid "Error enabling share: {error_message}"
-msgstr "Chyba při vysouvání zařízení: {error_message}"
+msgstr "Chyba při povolování sdílení: {error_message}"
#: plinth/modules/samba/views.py:112
-#, fuzzy
-#| msgid "Share edited."
msgid "Share disabled."
msgstr "Sdílení upraveno."
#: plinth/modules/samba/views.py:117
-#, fuzzy, python-brace-format
-#| msgid "Error ejecting device: {error_message}"
+#, python-brace-format
msgid "Error disabling share: {error_message}"
-msgstr "Chyba při vysouvání zařízení: {error_message}"
+msgstr "Chyba při zakázání sdílení: {error_message}"
#: plinth/modules/searx/__init__.py:22
msgid ""
@@ -6080,12 +6023,12 @@ msgstr "Zobrazit výkaz o zabezpečení"
#: plinth/modules/upgrades/templates/backports-firstboot.html:11
#: plinth/modules/upgrades/templates/upgrades_configure.html:44
msgid "Frequent Feature Updates"
-msgstr ""
+msgstr "Časté aktualizace funkcí"
#: plinth/modules/security/templates/security.html:21
#: plinth/modules/upgrades/templates/upgrades_configure.html:52
msgid "Frequent feature updates are activated."
-msgstr ""
+msgstr "Jsou aktivovány časté aktualizace funkcí."
#: plinth/modules/security/templates/security.html:26
#: plinth/modules/upgrades/templates/backports-firstboot.html:14
@@ -6100,6 +6043,12 @@ msgid ""
"Instead, they are maintained by contributors to Debian and the %(box_name)s "
"community."
msgstr ""
+"Časté aktualizace funkcí umožňují službě %(box_name)s a velmi omezené sadě "
+"softwaru častěji získávat nové funkce (z repozitáře backports). To vede k "
+"tomu, že některé nové funkce obdržíte během několika týdnů, místo abyste je "
+"dostávali přibližně jednou za dva roky. Všimněte si, že software s častými "
+"aktualizacemi funkcí nemá podporu bezpečnostního týmu Debianu. Místo toho se "
+"o ně starají přispěvatelé Debianu a komunita %(box_name)s."
#: plinth/modules/security/templates/security_report.html:10
#: plinth/modules/security/views.py:74
@@ -6112,6 +6061,8 @@ msgid ""
"There are %(count)s reported security vulnerabilities in the FreedomBox app, "
"which provides the core services and user interface for a FreedomBox server."
msgstr ""
+"V aplikaci FreedomBox, která poskytuje základní služby a uživatelské "
+"rozhraní serveru FreedomBox, je nahlášeno %(count)s bezpečnostních chyb."
#: plinth/modules/security/templates/security_report.html:19
msgid ""
@@ -6120,6 +6071,10 @@ msgid ""
"vulnerabilities can be found on the Debian Security Bug Tracker."
msgstr ""
+"V následující tabulce je uveden aktuální počet nahlášených bezpečnostních "
+"chyb pro každou nainstalovanou aplikaci. Další informace o zranitelnostech "
+"naleznete na Sledovači bezpečnostních chyb systému Debian."
#: plinth/modules/security/templates/security_report.html:28
msgid ""
@@ -6127,6 +6082,9 @@ msgid ""
"sandboxing features are in use. Sandboxing mitigates the impact of a "
"potentially compromised app to the rest of the system."
msgstr ""
+"U aplikací, které poskytují služby, sloupec \"Sandboxed\" ukazuje, zda jsou "
+"použity funkce sandboxu. Sandboxing zmírňuje dopad potenciálně napadené "
+"aplikace na zbytek systému."
#: plinth/modules/security/templates/security_report.html:35
msgid ""
@@ -6134,6 +6092,8 @@ msgid ""
"from the rest of the system. It is only displayed while the service is "
"running."
msgstr ""
+"\"Sandbox Coverage\" je hodnocení toho, jak efektivně je služba izolována od "
+"zbytku systému. Zobrazuje se pouze za běhu služby."
#: plinth/modules/security/templates/security_report.html:45
msgid "App Name"
@@ -6144,38 +6104,28 @@ msgid "Current Vulnerabilities"
msgstr "Stávající zranitelnosti zabezpečení"
#: plinth/modules/security/templates/security_report.html:47
-#, fuzzy
-#| msgid "Block Sandbox"
msgid "Sandboxed"
-msgstr "Pískoviště s kostkami"
+msgstr "Sandboxed"
#: plinth/modules/security/templates/security_report.html:48
-#, fuzzy
-#| msgid "Block Sandbox"
msgid "Sandbox Coverage"
-msgstr "Pískoviště s kostkami"
+msgstr "Sandbox pokrytí"
#: plinth/modules/security/templates/security_report.html:58
msgid "N/A"
-msgstr ""
+msgstr "N/A"
#: plinth/modules/security/templates/security_report.html:60
-#, fuzzy
-#| msgid "yes"
msgid "Yes"
msgstr "ano"
#: plinth/modules/security/templates/security_report.html:62
-#, fuzzy
-#| msgid "None"
msgid "No"
-msgstr "Žádný"
+msgstr "ne"
#: plinth/modules/security/templates/security_report.html:69
-#, fuzzy
-#| msgid "Tor is running"
msgid "Not running"
-msgstr "Tor je spuštěné"
+msgstr "Neprobíhá"
#: plinth/modules/security/views.py:56
#, python-brace-format
@@ -6191,18 +6141,12 @@ msgid "Shaarli allows you to save and share bookmarks."
msgstr "Shaarli umožňuje ukládat a sdílet záložky."
#: plinth/modules/shaarli/__init__.py:18
-#, fuzzy
-#| msgid ""
-#| "When enabled, Shaarli will be available from /"
-#| "shaarli path on the web server. Note that Shaarli only supports a "
-#| "single user account, which you will need to setup on the initial visit."
msgid ""
"Note that Shaarli only supports a single user account, which you will need "
"to setup on the initial visit."
msgstr ""
-"Když je zapnuté, Shaarli bude k dispozici v umístění /"
-"shaarli na webovém serveru. Poznamenejme, že Shaarli podporuje pouze "
-"jeden uživatelský účet, který bude třeba nastavit při první návštěvě."
+"Všimněte si, že Shaarli podporuje pouze jeden uživatelský účet, který je "
+"třeba nastavit při první návštěvě."
#: plinth/modules/shaarli/__init__.py:37 plinth/modules/shaarli/manifest.py:6
msgid "Shaarli"
@@ -6327,16 +6271,12 @@ 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
-#, fuzzy
-#| msgid ""
-#| "Users who have these permissions will also be able to read the files in "
-#| "the share."
msgid ""
"Users of the selected user groups will be able to read the files in the "
"share."
msgstr ""
-"Uživatelé kteří mají tato oprávnění budou také schopní číst soubory na "
-"sdílení."
+"Uživatelé vybraných skupin uživatelů budou moci číst soubory ve sdílené "
+"složce."
#: plinth/modules/sharing/forms.py:52
msgid "A share with this name already exists."
@@ -6345,6 +6285,7 @@ msgstr "Sdílení s tímto názvem už existuje."
#: plinth/modules/sharing/forms.py:63
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."
#: plinth/modules/sharing/templates/sharing.html:19
#: plinth/modules/sharing/templates/sharing.html:22
@@ -6499,16 +6440,12 @@ msgid "Yearly Snapshots Limit"
msgstr "Limit ročních zachycených stavů"
#: plinth/modules/snapshot/forms.py:49
-#, fuzzy
-#| msgid ""
-#| "Keep a maximum of this many yearly snapshots. The default value is 0 "
-#| "(disabled)."
msgid ""
"Keep a maximum of this many yearly snapshots. The default value is 0 (keep "
"no yearly snapshot)."
msgstr ""
-"Ponechat nejvýše tolik ročních zachycených stavů. Výchozí hodnota je 0 "
-"(ponechat všechny)."
+"Uchovávejte maximálně tento počet ročních snímků. Výchozí hodnota je 0 ("
+"neuchovává žádné roční snímky)."
#: plinth/modules/snapshot/templates/snapshot_delete_selected.html:12
msgid "Delete the following snapshots permanently?"
@@ -6542,11 +6479,11 @@ msgstr "Obnovit ze zálohy"
#: plinth/modules/snapshot/templates/snapshot_manage.html:40
msgid "will be used at next boot"
-msgstr ""
+msgstr "bude použita při příštím spuštění"
#: plinth/modules/snapshot/templates/snapshot_manage.html:45
msgid "in use"
-msgstr ""
+msgstr "v použití"
#: plinth/modules/snapshot/templates/snapshot_manage.html:54
#, python-format
@@ -6554,18 +6491,14 @@ msgid "Rollback to snapshot #%(number)s"
msgstr "Vrátit k zachycenému stavu č. %(number)s"
#: plinth/modules/snapshot/templates/snapshot_not_supported.html:11
-#, fuzzy, python-format
-#| msgid ""
-#| "Your have a filesystem of type %(fs_type)s. Snapshots "
-#| "are currently only available on %(types_supported)s "
-#| "filesystems."
+#, python-format
msgid ""
"You have a filesystem of type %(fs_type)s. Snapshots are "
"currently only available on %(types_supported)s filesystems."
msgstr ""
-"Používáte souborový systém typu %(fs_type)s. Zachycené "
-"stavy jsou v tuto chvíli k dispozici pouze na souborových systémech "
-"%(types_supported)s."
+"Používáte souborový systém typu %(fs_type)s. Snímky jsou v "
+"současné době k dispozici pouze na souborových systémech "
+"%(types_supported)s."
#: plinth/modules/snapshot/templates/snapshot_rollback.html:12
msgid "Roll back the system to this snapshot?"
@@ -6591,11 +6524,11 @@ msgstr "ručně vytvořen"
#: plinth/modules/snapshot/views.py:28
msgid "timeline"
-msgstr ""
+msgstr "časová osa"
#: plinth/modules/snapshot/views.py:29
msgid "apt"
-msgstr ""
+msgstr "apt"
#: plinth/modules/snapshot/views.py:39
msgid "Manage Snapshots"
@@ -6652,10 +6585,8 @@ msgid "Secure Shell (SSH) Server"
msgstr "Server zabezpečeného shellu (SSH)"
#: plinth/modules/ssh/forms.py:13
-#, fuzzy
-#| msgid "Use HTTP basic authentication"
msgid "Disable password authentication"
-msgstr "Použít základní HTTP ověřování"
+msgstr "Zakázat ověřování heslem"
#: plinth/modules/ssh/forms.py:14
msgid ""
@@ -6663,6 +6594,9 @@ msgid ""
"setup SSH keys in your administrator user account before enabling this "
"option."
msgstr ""
+"Zlepšuje zabezpečení tím, že zabraňuje hádání hesel. Před zapnutím této "
+"možnosti se ujistěte, že máte nastaveny klíče SSH v uživatelském účtu "
+"správce."
#: plinth/modules/ssh/templates/ssh.html:11
msgid "Server Fingerprints"
@@ -6673,6 +6607,8 @@ msgid ""
"When connecting to the server, ensure that the fingerprint shown by the SSH "
"client matches one of these fingerprints."
msgstr ""
+"Při připojování k serveru se ujistěte, že otisk prstu zobrazený klientem SSH "
+"odpovídá jednomu z těchto otisků."
#: plinth/modules/ssh/templates/ssh.html:24
msgid "Algorithm"
@@ -6685,12 +6621,12 @@ 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
-#, fuzzy
-#| msgid "Authentication to remote server failed."
msgid "SSH authentication with password enabled."
-msgstr "Ověření vůči vzdálenému serveru se nezdařilo."
+msgstr "Ověřování SSH s povoleným heslem."
#: plinth/modules/sso/__init__.py:28
msgid "Single Sign On"
@@ -6796,22 +6732,18 @@ msgid "The device is mounted by another user."
msgstr "Zařízení je připojeno jiným uživatelem."
#: plinth/modules/storage/__init__.py:317
-#, fuzzy, no-python-format, python-brace-format
-#| msgid ""
-#| "Warning: Low space on system partition ({percent_used}% used, "
-#| "{free_space} free)."
+#, no-python-format, python-brace-format
msgid "Low space on system partition: {percent_used}% used, {free_space} free."
msgstr ""
-"Varování: Dochází volné místo na systémovém oddílu ({percent_used}% využito, "
-"{free_space} volné)."
+"Málo místa na systémovém oddílu: {percent_used}% použito, {free_space} volné."
#: plinth/modules/storage/__init__.py:319
msgid "Low disk space"
-msgstr ""
+msgstr "Málo místa na disku"
#: plinth/modules/storage/__init__.py:347
msgid "Disk failure imminent"
-msgstr ""
+msgstr "Hrozí selhání disku"
#: plinth/modules/storage/__init__.py:349
#, python-brace-format
@@ -6819,50 +6751,44 @@ 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 ""
+"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
-#, fuzzy
-#| msgid "Invalid repository name."
msgid "Invalid directory name."
-msgstr "Neplatný název repozitáře."
+msgstr "Neplatný název adresáře."
#: plinth/modules/storage/forms.py:79
msgid "Directory does not exist."
-msgstr ""
+msgstr "Adresář neexistuje."
#: plinth/modules/storage/forms.py:82
msgid "Path is not a directory."
msgstr "Cesta není adresář."
#: plinth/modules/storage/forms.py:85
-#, fuzzy
-#| msgid "The device is mounted by another user."
msgid "Directory is not readable by the user."
-msgstr "Zařízení je připojeno jiným uživatelem."
+msgstr "Adresář není pro uživatele čitelný."
#: plinth/modules/storage/forms.py:88
msgid "Directory is not writable by the user."
-msgstr ""
+msgstr "Do adresáře nemůže uživatel zapisovat."
#: plinth/modules/storage/forms.py:93
-#, fuzzy
-#| msgid "Download directory"
msgid "Directory"
-msgstr "Složka pro stahování"
+msgstr "Adresář"
#: plinth/modules/storage/forms.py:95
msgid "Subdirectory (optional)"
-msgstr ""
+msgstr "Podadresář (volitelné)"
#: plinth/modules/storage/forms.py:142
-#, fuzzy
-#| msgid "Shared"
msgid "Share"
-msgstr "Sdílené"
+msgstr "Sdílet"
#: plinth/modules/storage/forms.py:150
msgid "Other directory (specify below)"
-msgstr ""
+msgstr "Jiný adresář (uveďte níže)"
#: plinth/modules/storage/templates/storage.html:17
msgid "The following storage devices are in use:"
@@ -6906,6 +6832,8 @@ msgid ""
"Advanced storage operations such as disk partitioning and RAID management "
"are provided by the Cockpit app."
msgstr ""
+"Pokročilé operace s úložištěm, jako je rozdělení disku a správa pole RAID, "
+"zajišťuje aplikace Cockpit."
#: plinth/modules/storage/templates/storage_expand.html:14
#, python-format
@@ -6953,14 +6881,7 @@ msgstr ""
"zařízení, na kterých také provozujete Syncthing."
#: plinth/modules/syncthing/__init__.py:28
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "Running Syncthing on {box_name} provides an extra synchronization point "
-#| "for your data that is available most of the time, allowing your devices "
-#| "to synchronize more often. {box_name} runs a single instance of "
-#| "Syncthing that may be used by multiple users. Each user's set of devices "
-#| "may be synchronized with a distinct set of folders. The web interface on "
-#| "{box_name} is only available for users belonging to the \"admin\" group."
+#, python-brace-format
msgid ""
"Running Syncthing on {box_name} provides an extra synchronization point for "
"your data that is available most of the time, allowing your devices to "
@@ -6970,12 +6891,13 @@ msgid ""
"{box_name} is only available for users belonging to the \"admin\" or "
"\"syncthing-access\" group."
msgstr ""
-"Provozování Syncthing na {box_name} poskytuje další synchronizační bod pro "
-"vaše data, který je k dispozici po většinu času, což umožní vašim zařízením "
-"synchronizovat častěji. {box_name} provozuje jednu instanci Syncthing která "
-"může být používána vícero uživateli. Sada zařízení každého z uživatelů může "
-"být synchronizována do odlišné sady složek. Webové rozhraní {box_name} je k "
-"dispozici pouze pro uživatele náležející do skupiny „admin“."
+"Spuštění Syncthing na {box_name} poskytuje další synchronizační bod pro vaše "
+"data, který je k dispozici po většinu času, což umožňuje častější "
+"synchronizaci vašich zařízení. Na {box_name} je spuštěna jedna instance "
+"Syncthing, kterou může používat více uživatelů. Sada zařízení každého "
+"uživatele může být synchronizována s odlišnou sadou složek. Webové rozhraní "
+"na {box_name} je dostupné pouze pro uživatele patřící do skupiny \"admin\" "
+"nebo \"syncthing-access\"."
#: plinth/modules/syncthing/__init__.py:57
msgid "Administer Syncthing application"
@@ -7074,10 +6996,8 @@ msgid "Tor"
msgstr "Tor"
#: plinth/modules/tor/__init__.py:67
-#, fuzzy
-#| msgid "Tor Hidden Service"
msgid "Tor Onion Service"
-msgstr "Tor skrytá služba"
+msgstr "Tor Onion Service"
#: plinth/modules/tor/__init__.py:71
msgid "Tor Socks Proxy"
@@ -7177,25 +7097,19 @@ msgstr ""
"Toto ostatním pomůže obcházet cenzuru."
#: plinth/modules/tor/forms.py:105
-#, fuzzy
-#| msgid "Enable Tor Hidden Service"
msgid "Enable Tor Hidden Service"
msgstr "Zapnout Tor skrytou službu"
#: plinth/modules/tor/forms.py:107
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "A hidden service will allow {box_name} to provide selected services (such "
-#| "as wiki or chat) without revealing its location. Do not use this for "
-#| "strong anonymity yet."
+#, python-brace-format
msgid ""
"A hidden service will allow {box_name} to provide selected services (such as "
"wiki or chat) without revealing its location. Do not use this for strong "
"anonymity yet."
msgstr ""
-"Skrytá služba umožní {box_name} poskytovat vybrané služby (jako wiki nebo "
-"chat) bez odhalení jeho polohy. Toto prozatím nepoužívejte, pokud "
-"potřebujete silnou anonymitu."
+"Skrytá služba umožní {box_name} poskytovat vybrané služby (například wiki "
+"nebo chat), aniž by bylo odhaleno její umístění. Pro silnou anonymitu ji "
+"zatím nepoužívejte."
#: plinth/modules/tor/forms.py:112
msgid "Download software packages over Tor"
@@ -7228,10 +7142,8 @@ msgid "Tor configuration is being updated"
msgstr "Nastavení Tor jsou aktualizována"
#: plinth/modules/tor/templates/tor.html:26
-#, fuzzy
-#| msgid "Hidden Service"
msgid "Onion Service"
-msgstr "Skrytá služba"
+msgstr "Onion služba"
#: plinth/modules/tor/templates/tor.html:28
msgid "Ports"
@@ -7271,21 +7183,16 @@ msgstr ""
"rozhraní."
#: plinth/modules/transmission/__init__.py:25
-#, fuzzy
-#| msgid ""
-#| "BitTorrent is a peer-to-peer file sharing protocol. Transmission daemon "
-#| "handles Bitorrent file sharing. Note that BitTorrent is not anonymous."
msgid ""
"BitTorrent is a peer-to-peer file sharing protocol. Note that BitTorrent is "
"not anonymous."
msgstr ""
-"BitTorrent je protokol pro sdílení souborů mezi sebou. Proces služby "
-"Transmision obsluhuje sdílení souborů Bitorrent. Poznamenejme, že BitTorrent "
-"není anonymní."
+"BitTorrent je protokol pro sdílení souborů peer-to-peer. Všimněte si, že "
+"BitTorrent není anonymní."
#: plinth/modules/transmission/__init__.py:27
msgid "Please do not change the default port of the transmission daemon."
-msgstr ""
+msgstr "Výchozí port přenosového démona neměňte."
#: plinth/modules/transmission/__init__.py:53
#: plinth/modules/transmission/manifest.py:6
@@ -7302,30 +7209,21 @@ msgstr ""
"odkudkoli, ale s pohodlím podobným desktopové aplikaci."
#: plinth/modules/ttrss/__init__.py:27
-#, fuzzy, python-brace-format
-#| msgid ""
-#| "When enabled, Tiny Tiny RSS will be available from /"
-#| "tt-rss path on the web server. It 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 with a {box_name} login."
msgstr ""
-"Pokud je zapnuto, Tiny Tiny RSS bude k dispozici v umístění /tt-rss umístění na webovém serveru. Je přístupné pro libovolného uživatele s účtem na {box_name}."
+"Pokud je funkce Tiny Tiny RSS povolena, může k ní přistupovat každý uživatel s přihlašovacím jménem {box_name}."
#: plinth/modules/ttrss/__init__.py:31
-#, fuzzy
-#| msgid ""
-#| "When using a mobile or desktop application for Tiny Tiny RSS, use the URL "
-#| "/tt-rss-app for connecting."
msgid ""
"When using a mobile or desktop application for Tiny Tiny RSS, use the URL /tt-rss-app for connecting."
msgstr ""
-"Při používání mobilní nebo desktopové aplikace pro Tiny Tiny RSS použijte "
-"pro připojování URL adresu /tt-rss-app."
+"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:49
msgid "Read and subscribe to news feeds"
@@ -7356,6 +7254,11 @@ msgid ""
"to be unavailable briefly. If system reboot is deemed necessary, it is done "
"automatically at 02:00 causing all apps to be unavailable briefly."
msgstr ""
+"Aktualizace probíhají každý den v 06:00 podle místního časového pásma. "
+"Nastavte si časové pásmo v aplikaci Datum a čas. Aplikace se po aktualizaci "
+"restartují, což způsobí jejich krátkodobou nedostupnost. Pokud je restart "
+"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:74
#: plinth/modules/upgrades/templates/update-firstboot-progress.html:11
@@ -7365,20 +7268,16 @@ msgid "Update"
msgstr "Aktualizovat"
#: plinth/modules/upgrades/__init__.py:129
-#, fuzzy
-#| msgid "Update"
msgid "Updates"
-msgstr "Aktualizovat"
+msgstr "Aktualizace"
#: plinth/modules/upgrades/__init__.py:132
-#, fuzzy
-#| msgid "FreedomBox Foundation"
msgid "FreedomBox Updated"
-msgstr "Nadace FreedomBox"
+msgstr "FreedomBox aktualizován"
#: plinth/modules/upgrades/__init__.py:217
msgid "Could not start distribution update"
-msgstr ""
+msgstr "Nelze spustit aktualizaci distribuce"
#: plinth/modules/upgrades/__init__.py:219
msgid ""
@@ -7386,17 +7285,19 @@ msgid ""
"distribution update. Please ensure at least 5 GB is free. Distribution "
"update will be retried after 24 hours, if enabled."
msgstr ""
+"V kořenovém oddílu není dostatek volného místa pro spuštění aktualizace "
+"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:230
-#, fuzzy
-#| msgid "Automatic upgrades disabled"
msgid "Distribution update started"
-msgstr "Automatické aktualizace vypnuty"
+msgstr "Zahájena aktualizace distribuce"
#: plinth/modules/upgrades/__init__.py:232
msgid ""
"Started update to next stable release. This may take a long time to complete."
msgstr ""
+"Zahájena aktualizace na další stabilní verzi. Dokončení může trvat dlouho."
#: plinth/modules/upgrades/forms.py:15
msgid "Enable auto-update"
@@ -7407,61 +7308,56 @@ msgid "When enabled, FreedomBox automatically updates once a day."
msgstr "Když je zapnuto, FreedomBox se jednou denně automaticky zaktualizuje."
#: plinth/modules/upgrades/forms.py:19
-#, fuzzy
-#| msgid "Enable auto-update"
msgid "Enable auto-update to next stable release"
-msgstr "Zapnout automatické aktualizace"
+msgstr "Povolení automatické aktualizace na další stabilní verzi"
#: plinth/modules/upgrades/forms.py:20
msgid ""
"When enabled, FreedomBox will update to the next stable distribution release "
"when it is available."
msgstr ""
+"Pokud je tato možnost povolena, bude FreedomBox aktualizován na další "
+"stabilní verzi distribuce, jakmile bude k dispozici."
#: plinth/modules/upgrades/forms.py:34
#: plinth/modules/upgrades/templates/upgrades_configure.html:89
msgid "Activate frequent feature updates (recommended)"
-msgstr ""
+msgstr "Aktivujte časté aktualizace funkcí (doporučeno)"
#: plinth/modules/upgrades/forms.py:40
-#, fuzzy
-#| msgid "Fail2Ban (recommended)"
msgid "Update now (recommended)"
-msgstr "Fail2Ban (doporučeno)"
+msgstr "Aktualizovat nyní (doporučeno)"
#: plinth/modules/upgrades/templates/backports-firstboot.html:26
msgid ""
"It is strongly recommended to activate frequent feature updates. If not "
"activated now, they can be activated later."
msgstr ""
+"Důrazně se doporučuje aktivovat časté aktualizace funkcí. Pokud nejsou "
+"aktivovány nyní, lze je aktivovat později."
#: plinth/modules/upgrades/templates/backports-firstboot.html:33
msgid ""
"Note: Once frequent feature updates are activated, they "
"cannot be deactivated."
msgstr ""
+"Poznámka: Jakmile jsou časté aktualizace funkcí aktivovány, "
+"nelze je deaktivovat."
#: plinth/modules/upgrades/templates/update-firstboot-progress.html:19
-#, fuzzy
-#| msgid "Updating..."
msgid "Updating, please wait..."
-msgstr "Aktualizace…"
+msgstr "Aktualizace, počkejte prosím..."
#: plinth/modules/upgrades/templates/update-firstboot-progress.html:22
#: plinth/modules/upgrades/templates/update-firstboot.html:20
-#, fuzzy
-#| msgid ""
-#| "This may take a long time to complete. During an update, "
-#| "you can not install apps. Also, this web interface may be temporarily "
-#| "unavailable and show an error. In that case, refresh the page to continue."
msgid ""
"This may take a long time to complete. During an update, "
"this web interface may be temporarily unavailable and show an error. In that "
"case, refresh the page to continue."
msgstr ""
-"Dokončení tohoto může trvat dlouhou dobu. V průběhu "
-"aktualizace není možné instalovat aplikace. Také webové rozhraní může být "
-"dočasně nedostupné a zobrazovat chybu. V takovém případě ho načtěte znovu."
+"Dokončení aktualizace může trvat dlouho. Během aktualizace "
+"může být toto webové rozhraní dočasně nedostupné a může se zobrazit chyba. V "
+"takovém případě obnovte stránku a pokračujte."
#: plinth/modules/upgrades/templates/update-firstboot-progress.html:31
#, python-format
@@ -7485,11 +7381,13 @@ msgid ""
"%(box_name)s has been updated to version %(version)s. See the release announcement."
msgstr ""
+"%(box_name)s byl aktualizován na verzi %(version)s. Viz oznámení o vydání."
#: plinth/modules/upgrades/templates/upgrades-new-release.html:22
#: plinth/templates/notifications.html:44
msgid "Dismiss"
-msgstr ""
+msgstr "Odmítnout"
#: plinth/modules/upgrades/templates/upgrades_configure.html:30
#: plinth/modules/upgrades/templates/upgrades_configure.html:100
@@ -7508,13 +7406,15 @@ msgstr "Váš Freedombox potřebuje aktualizaci!"
#: plinth/modules/upgrades/templates/upgrades_configure.html:47
msgid ""
"Frequent feature updates can be activated. Activating them is recommended."
-msgstr ""
+msgstr "Lze aktivovat časté aktualizace funkcí. Jejich aktivace se doporučuje."
#: plinth/modules/upgrades/templates/upgrades_configure.html:56
msgid ""
"Frequent feature updates cannot be activated. They may not be necessary on "
"your distribution."
msgstr ""
+"Časté aktualizace funkcí nelze aktivovat. Ve vaší distribuci nemusí být "
+"nutné."
#: plinth/modules/upgrades/templates/upgrades_configure.html:78
#, python-format
@@ -7523,10 +7423,11 @@ msgid ""
"cannot be deactivated. You may wish to take a snapshot using Storage Snapshots before continuing."
msgstr ""
+"Upozornění! Jakmile jsou časté aktualizace funkcí "
+"aktivovány, nelze je deaktivovat. Před pokračováním můžete provést snímek "
+"pomocí Snímky úložiště."
#: plinth/modules/upgrades/templates/upgrades_configure.html:94
-#, fuzzy
-#| msgid "Manual update"
msgid "Manual Update"
msgstr "Ruční aktualizace"
@@ -7535,25 +7436,18 @@ msgid "Update now"
msgstr "Aktualizovat nyní"
#: plinth/modules/upgrades/templates/upgrades_configure.html:114
-#, fuzzy
-#| msgid ""
-#| "This may take a long time to complete. During an update, "
-#| "you can not install apps. Also, this web interface may be temporarily "
-#| "unavailable and show an error. In that case, refresh the page to continue."
msgid ""
"This may take a long time to complete. During an update, "
"you cannot install apps. Also, this web interface may be temporarily "
"unavailable and show an error. In that case, refresh the page to continue."
msgstr ""
-"Dokončení tohoto může trvat dlouhou dobu. V průběhu "
-"aktualizace není možné instalovat aplikace. Také webové rozhraní může být "
-"dočasně nedostupné a zobrazovat chybu. V takovém případě ho načtěte znovu."
+"To může trvat dlouho. Během aktualizace nelze instalovat "
+"aplikace. Také toto webové rozhraní může být dočasně nedostupné a zobrazovat "
+"chybu. V takovém případě obnovte stránku a pokračujte."
#: plinth/modules/upgrades/templates/upgrades_configure.html:128
-#, fuzzy
-#| msgid "Toggle recent update logs"
msgid "Show recent update logs"
-msgstr "Vyp/zap. záznamy událostí při nedávných aktualizacích"
+msgstr "Zobrazit protokoly posledních aktualizací"
#: plinth/modules/upgrades/views.py:67
#, python-brace-format
@@ -7569,16 +7463,12 @@ msgid "Automatic upgrades disabled"
msgstr "Automatické aktualizace vypnuty"
#: plinth/modules/upgrades/views.py:82
-#, fuzzy
-#| msgid "Automatic upgrades enabled"
msgid "Distribution upgrade enabled"
-msgstr "Automatické aktualizace zapnuty"
+msgstr "Upgrade distribuce povoleno"
#: plinth/modules/upgrades/views.py:85
-#, fuzzy
-#| msgid "Automatic upgrades disabled"
msgid "Distribution upgrade disabled"
-msgstr "Automatické aktualizace vypnuty"
+msgstr "Upgrade distribuce zakázáno"
#: plinth/modules/upgrades/views.py:127
msgid "Upgrade process started."
@@ -7590,7 +7480,7 @@ msgstr "Spouštění přechodu na novější verzi se nezdařilo."
#: plinth/modules/upgrades/views.py:139
msgid "Frequent feature updates activated."
-msgstr ""
+msgstr "Aktivovány časté aktualizace funkcí."
#: plinth/modules/users/__init__.py:29
msgid ""
@@ -7598,6 +7488,10 @@ msgid ""
"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 ""
+"Vytváření a správa uživatelských účtů. Tyto účty slouží jako centralizovaný "
+"mechanismus ověřování pro většinu aplikací. Některé aplikace dále vyžadují, "
+"aby uživatelský účet byl součástí skupiny, která uživatele opravňuje k "
+"přístupu k aplikaci."
#: plinth/modules/users/__init__.py:34
#, python-brace-format
@@ -7606,6 +7500,10 @@ msgid ""
"relevant to them in the home page. However, only users of the admin "
"group may alter apps or system settings."
msgstr ""
+"Každý uživatel se může přihlásit do webového rozhraní {box_name} a na "
+"domovské stránce si zobrazit seznam aplikací, které se ho týkají. Aplikace "
+"nebo nastavení systému však mohou měnit pouze uživatelé skupiny "
+"admin."
#: plinth/modules/users/__init__.py:57
msgid "Users and Groups"
@@ -7633,29 +7531,21 @@ msgstr "Zadejte platné uživatelské jméno."
msgid ""
"Required. 150 characters or fewer. English letters, digits and @/./-/_ only."
msgstr ""
+"Požadováno. Nejvýše 150 znaků. Pouze anglická písmena, číslice a @/./-/_."
#: plinth/modules/users/forms.py:78
-#, fuzzy
-#| msgid "Administrator Password"
msgid "Authorization Password"
-msgstr "Heslo k účtu správce"
+msgstr "Autorizační heslo"
#: plinth/modules/users/forms.py:79
msgid "Enter your current password to authorize account modifications."
-msgstr ""
+msgstr "Zadejte své aktuální heslo a autorizujte změny účtu."
#: plinth/modules/users/forms.py:87
msgid "Invalid password."
msgstr "Neplatné heslo."
#: plinth/modules/users/forms.py:104
-#, fuzzy
-#| 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 are in the appropriate group.
Users in the admin group "
-#| "will be able to log in to all services. They can also log in to the "
-#| "system through SSH and have administrative privileges (sudo)."
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 "
@@ -7663,11 +7553,11 @@ msgid ""
"able to log in to all services. They can also log in to the system through "
"SSH and have administrative privileges (sudo)."
msgstr ""
-"Vyberte které služby by měly být novému uživateli k dispozici. Uživatel bude "
-"schopen se přihlásit ke službám, které podporují sdružené přihlašování (SSO) "
-"přes LDAP, pokud je členem příslušné skupiny.
Uživatelé ve "
-"skupině správců (admin) se budou moci přihlásit všude. Mohou se k systému "
-"přihlásit také prostřednictvím SSH a mají práva správy (sudo)."
+"Vyberte, které služby mají být novému uživateli k dispozici. Uživatel se "
+"bude moci přihlásit ke službám, které podporují jednotné přihlášení "
+"prostřednictvím LDAP, pokud je v příslušné skupině.
Uživatelé ve "
+"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:149 plinth/modules/users/forms.py:393
#, python-brace-format
@@ -7675,10 +7565,9 @@ msgid "Creating LDAP user failed: {error}"
msgstr "Vytvoření uživatele LDAP se nezdařilo: {error}"
#: plinth/modules/users/forms.py:162
-#, fuzzy, python-brace-format
-#| msgid "Failed to add new user to {group} group."
+#, python-brace-format
msgid "Failed to add new user to {group} group: {error}"
-msgstr "Přidání nového uživatele do skupiny {group} se nezdařilo."
+msgstr "Nepodařilo se přidat nového uživatele do skupiny {group}: {error}"
#: plinth/modules/users/forms.py:176
msgid "Authorized SSH Keys"
@@ -7711,26 +7600,22 @@ msgid "Unable to set SSH keys."
msgstr "Nepodařilo se vložit SSH klíče."
#: plinth/modules/users/forms.py:319
-#, fuzzy
-#| msgid "Failed to add user to group."
msgid "Failed to change user status."
-msgstr "Přidání uživatele do skupiny se nezdařilo."
+msgstr "Nepodařilo se změnit stav uživatele."
#: plinth/modules/users/forms.py:364
msgid "Changing LDAP user password failed."
msgstr "Změna hesla LDAP uživatele se nezdařila."
#: plinth/modules/users/forms.py:404
-#, fuzzy, python-brace-format
-#| msgid "Failed to add new user to admin group."
+#, python-brace-format
msgid "Failed to add new user to admin group: {error}"
-msgstr "Přidání nového uživatele do skupiny správců (admin) se nezdařilo."
+msgstr "Nepodařilo se přidat nového uživatele do skupiny admin: {error}"
#: plinth/modules/users/forms.py:423
-#, fuzzy, python-brace-format
-#| msgid "Failed to restrict console access."
+#, python-brace-format
msgid "Failed to restrict console access: {error}"
-msgstr "Omezení přístupu ke konzoli se nezdařilo."
+msgstr "Nepodařilo se omezit přístup ke konzole: {error}"
#: plinth/modules/users/forms.py:436
msgid "User account created, you are now logged in"
@@ -7787,16 +7672,12 @@ msgid "Create Account"
msgstr "Vytvořit účet"
#: plinth/modules/users/templates/users_firstboot.html:32
-#, fuzzy
-#| msgid "Administrator Account"
msgid "An administrator account already exists."
-msgstr "Účet správce"
+msgstr "Účet správce již existuje."
#: plinth/modules/users/templates/users_firstboot.html:38
-#, fuzzy
-#| msgid "Cannot delete the only administrator in the system."
msgid "The following administrator accounts exist in the system."
-msgstr "Není možné smazat účet jediného zbývajícího správce systému."
+msgstr "V systému existují následující účty správců."
#: plinth/modules/users/templates/users_firstboot.html:50
#, python-format, python-brace-format
@@ -7807,6 +7688,11 @@ msgid ""
"{username}'. 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 "
+"'echo \"{password}\". | /usr/share/plinth/actions/users remove-user "
+"{username}\". Pokud je účet již použitelný s %(box_name)s, tento krok "
+"přeskočte."
#: plinth/modules/users/templates/users_list.html:11
#: plinth/modules/users/views.py:61
@@ -7824,8 +7710,7 @@ msgid "Delete user %(username)s"
msgstr "Smazat uživatele %(username)s"
#: plinth/modules/users/templates/users_update.html:11
-#, fuzzy, python-format
-#| msgid "Edit user %(username)s"
+#, python-format
msgid "Edit User %(username)s"
msgstr "Upravit uživatele %(username)s"
@@ -7835,8 +7720,8 @@ msgid ""
"Use the change password form to "
"change the password."
msgstr ""
-"Heslo změníte pomocí formuláře pro změnu "
-"hesla."
+"Pro změnu hesla použijte formulář změna "
+"hesla ."
#: plinth/modules/users/templates/users_update.html:31
#: plinth/templates/language-selection.html:17
@@ -7876,7 +7761,7 @@ msgstr "Heslo úspěšně změněno."
#: plinth/modules/wireguard/__init__.py:20
msgid "WireGuard is a fast, modern, secure VPN tunnel."
-msgstr ""
+msgstr "WireGuard je rychlý, moderní a bezpečný tunel VPN."
#: plinth/modules/wireguard/__init__.py:22
#, python-brace-format
@@ -7884,6 +7769,8 @@ msgid ""
"It can be used to connect to a VPN provider which supports WireGuard, and to "
"route all outgoing traffic from {box_name} through the VPN."
msgstr ""
+"Lze jej použít k připojení k poskytovateli VPN, který podporuje službu "
+"WireGuard, a ke směrování veškerého odchozího provozu z {box_name} přes VPN."
#: plinth/modules/wireguard/__init__.py:26
#, python-brace-format
@@ -7892,55 +7779,55 @@ msgid ""
"travelling. While connected to a public Wi-Fi network, all traffic can be "
"securely relayed through {box_name}."
msgstr ""
+"Druhým případem použití je připojení mobilního zařízení k {box_name} na "
+"cestách. Při připojení k veřejné síti Wi-Fi může být veškerý provoz bezpečně "
+"přenášen přes {box_name}."
#: plinth/modules/wireguard/forms.py:32
-#, fuzzy
-#| msgid "Invalid kite name"
msgid "Invalid key."
-msgstr "Neplatný kite název"
+msgstr "Neplatný klíč."
#: plinth/modules/wireguard/forms.py:61
#: plinth/modules/wireguard/templates/wireguard.html:17
#: plinth/modules/wireguard/templates/wireguard.html:77
#: plinth/modules/wireguard/templates/wireguard_delete_server.html:24
-#, fuzzy
-#| msgid "Publish Key"
msgid "Public Key"
-msgstr "Zveřejnit klíč"
+msgstr "Veřejný klíč"
#: plinth/modules/wireguard/forms.py:62
msgid ""
"Public key of the peer. Example: "
"MConEJFIg6+DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs= ."
msgstr ""
+"Veřejný klíč partnera. Příklad: MConEJFIg6+DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs= "
+"."
#: plinth/modules/wireguard/forms.py:70
msgid "Endpoint of the server"
-msgstr ""
+msgstr "Koncový bod serveru"
#: plinth/modules/wireguard/forms.py:71
msgid ""
"Domain name and port in the form \"ip:port\". Example: demo.wireguard."
"com:12912 ."
msgstr ""
+"Název domény a port ve tvaru \"ip:port\". Příklad: demo.wireguard.com:12912 ."
#: plinth/modules/wireguard/forms.py:76
-#, fuzzy
-#| msgid "Published key to keyserver."
msgid "Public key of the server"
-msgstr "Klíč zveřejněn na server s klíči."
+msgstr "Veřejný klíč serveru"
#: plinth/modules/wireguard/forms.py:77
msgid ""
"Provided by the server operator, a long string of characters. Example: "
"MConEJFIg6+DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs= ."
msgstr ""
+"Poskytuje provozovatel serveru, dlouhý řetězec znaků. Příklad: MConEJFIg6+"
+"DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs= ."
#: plinth/modules/wireguard/forms.py:82
-#, fuzzy
-#| msgid "A list of IP addresses, separated by space"
msgid "Client IP address provided by server"
-msgstr "Seznam IP adres, jednotlivé položky oddělujte mezerou"
+msgstr "IP adresa klienta poskytnutá serverem"
#: plinth/modules/wireguard/forms.py:83
msgid ""
@@ -7948,10 +7835,13 @@ msgid ""
"endpoint. This value is usually provided by the server operator. Example: "
"192.168.0.10."
msgstr ""
+"IP adresa přiřazená tomuto počítači v síti VPN po připojení ke koncovému "
+"bodu. Tuto hodnotu obvykle poskytuje provozovatel serveru. Příklad: 192.168.0"
+".10."
#: plinth/modules/wireguard/forms.py:89
msgid "Private key of this machine"
-msgstr ""
+msgstr "Soukromý klíč tohoto stroje"
#: plinth/modules/wireguard/forms.py:90
msgid ""
@@ -7960,10 +7850,14 @@ msgid ""
"some server operators insist on providing this. Example: "
"MConEJFIg6+DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs= ."
msgstr ""
+"Volitelně. Pokud je ponecháno prázdné, jsou generovány nové veřejné/soukromé "
+"klíče. Veřejný klíč pak lze poskytnout serveru. Jedná se o doporučený "
+"způsob. Někteří provozovatelé serverů však na jeho poskytnutí trvají. "
+"Příklad: MConEJFIg6+DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs= ."
#: plinth/modules/wireguard/forms.py:98
msgid "Pre-shared key"
-msgstr ""
+msgstr "Předem sdílený klíč"
#: plinth/modules/wireguard/forms.py:99
msgid ""
@@ -7971,127 +7865,105 @@ msgid ""
"layer of security. Fill in only if provided. Example: "
"MConEJFIg6+DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs=."
msgstr ""
+"Volitelně. Sdílený tajný klíč poskytnutý serverem, který přidává další "
+"vrstvu zabezpečení. Vyplňte pouze v případě, že byl poskytnut. Příklad: "
+"MConEJFIg6+DFHg2J1nn9SNLOSE9KR0ysdPgmPjibEs=."
#: plinth/modules/wireguard/forms.py:105
msgid "Use this connection to send all outgoing traffic"
-msgstr ""
+msgstr "Toto připojení slouží k odesílání veškerého odchozího provozu"
#: plinth/modules/wireguard/forms.py:107
msgid "Typically checked for a VPN service though which all traffic is sent."
msgstr ""
+"Obvykle se kontroluje u služby VPN, přes kterou se odesílá veškerý provoz."
#: plinth/modules/wireguard/templates/wireguard.html:10
-#, fuzzy
-#| msgid "Chat Server"
msgid "As a Server"
-msgstr "Chat server"
+msgstr "Jako server"
#: plinth/modules/wireguard/templates/wireguard.html:12
msgid "Peers allowed to connect to this server:"
-msgstr ""
+msgstr "Peery s povolením připojit se k tomuto serveru:"
#: plinth/modules/wireguard/templates/wireguard.html:18
msgid "Allowed IPs"
-msgstr ""
+msgstr "Povolené IP adresy"
#: plinth/modules/wireguard/templates/wireguard.html:19
#: plinth/modules/wireguard/templates/wireguard.html:78
-#, fuzzy
-#| msgid "Create Connection"
msgid "Last Connected Time"
-msgstr "Vytvořit připojení"
+msgstr "Čas posledního připojení"
#: plinth/modules/wireguard/templates/wireguard.html:38
#, python-format
msgid "No peers configured to connect to this %(box_name)s yet."
-msgstr ""
+msgstr "K tomuto %(box_name)s zatím není nakonfigurován žádný partner."
#: plinth/modules/wireguard/templates/wireguard.html:48
#, python-format
msgid "Public key for this %(box_name)s:"
-msgstr ""
+msgstr "Veřejný klíč pro tento %(box_name)s:"
#: plinth/modules/wireguard/templates/wireguard.html:54
-#, fuzzy
-#| msgid "No shares currently configured."
msgid "Not configured yet."
-msgstr "Nyní není nastavené žádné sdílení."
+msgstr "Zatím není nakonfigurováno."
#: plinth/modules/wireguard/templates/wireguard.html:59
-#, fuzzy
-#| msgid "Add new introducer"
msgid "Add a new peer"
-msgstr "Přidat nový uvaděč"
+msgstr "Přidání nového peeru"
#: plinth/modules/wireguard/templates/wireguard.html:63
#: plinth/modules/wireguard/views.py:48
msgid "Add Allowed Client"
-msgstr ""
+msgstr "Přidat povoleného klienta"
#: plinth/modules/wireguard/templates/wireguard.html:67
-#, fuzzy
-#| msgid "Chat Client"
msgid "As a Client"
-msgstr "Chatovací klient"
+msgstr "Jako klient"
#: plinth/modules/wireguard/templates/wireguard.html:69
#, python-format
msgid "Servers that %(box_name)s will connect to:"
-msgstr ""
+msgstr "Servery, ke kterým se %(box_name)s připojí:"
#: plinth/modules/wireguard/templates/wireguard.html:76
#: plinth/modules/wireguard/templates/wireguard_delete_server.html:20
msgid "Endpoint"
-msgstr ""
+msgstr "Koncový bod"
#: plinth/modules/wireguard/templates/wireguard.html:99
-#, fuzzy
-#| msgid "Authentication to remote server failed."
msgid "No connections to remote servers are configured yet."
-msgstr "Ověření vůči vzdálenému serveru se nezdařilo."
+msgstr "Zatím nejsou nakonfigurována žádná připojení ke vzdáleným serverům."
#: plinth/modules/wireguard/templates/wireguard.html:109
-#, fuzzy
-#| msgid "Add new introducer"
msgid "Add a new server"
-msgstr "Přidat nový uvaděč"
+msgstr "Přidat nový server"
#: plinth/modules/wireguard/templates/wireguard.html:113
#: plinth/modules/wireguard/views.py:157
-#, fuzzy
-#| msgid "Add Connection"
msgid "Add Connection to Server"
-msgstr "Přidat připojení"
+msgstr "Přidat připojení k serveru"
#: plinth/modules/wireguard/templates/wireguard_add_client.html:19
-#, fuzzy
-#| msgid "IRC Client"
msgid "Add Client"
-msgstr "IRC klient"
+msgstr "Přidat klienta"
#: plinth/modules/wireguard/templates/wireguard_delete_client.html:14
-#, fuzzy
-#| msgid "Are you sure that you want to remove this repository?"
msgid "Are you sure that you want to delete this client?"
-msgstr "Opravdu chcete tento repozitář odebrat?"
+msgstr "Jste si jisti, že chcete tohoto klienta odstranit?"
#: plinth/modules/wireguard/templates/wireguard_delete_server.html:14
-#, fuzzy
-#| msgid "Are you sure that you want to remove this repository?"
msgid "Are you sure that you want to delete this server?"
-msgstr "Opravdu chcete tento repozitář odebrat?"
+msgstr "Jste si jisti, že chcete tento server odstranit?"
#: plinth/modules/wireguard/templates/wireguard_edit_client.html:19
-#, fuzzy
-#| msgid "Chat Client"
msgid "Update Client"
-msgstr "Chatovací klient"
+msgstr "Aktualizace klienta"
#: plinth/modules/wireguard/templates/wireguard_edit_server.html:19
-#, fuzzy
-#| msgid "Create Connection"
msgid "Update Connection"
-msgstr "Vytvořit připojení"
+msgstr "Connection updates"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:12
#, python-format
@@ -8099,19 +7971,21 @@ msgid ""
"%(box_name)s will allow this client to connect to it. Ensure that the client "
"is configured with the following information."
msgstr ""
+"%(box_name)s umožní tomuto klientovi se k němu připojit. Ujistěte se, že je "
+"klient nakonfigurován s následujícími informacemi."
#: plinth/modules/wireguard/templates/wireguard_show_client.html:21
msgid "Client public key:"
-msgstr ""
+msgstr "Veřejný klíč klienta:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:25
msgid "IP address to use for client:"
-msgstr ""
+msgstr "IP adresa, která se použije pro klienta:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:29
#: plinth/modules/wireguard/templates/wireguard_show_server.html:32
msgid "Pre-shared key:"
-msgstr ""
+msgstr "Předem sdílený klíč:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:33
msgid "Server endpoints:"
@@ -8125,17 +7999,17 @@ msgstr "Veřejný klíč serveru:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:53
#: plinth/modules/wireguard/templates/wireguard_show_server.html:52
msgid "Data transmitted:"
-msgstr ""
+msgstr "Přenášená data:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:57
#: plinth/modules/wireguard/templates/wireguard_show_server.html:56
msgid "Data received:"
-msgstr ""
+msgstr "Přijatá data:"
#: plinth/modules/wireguard/templates/wireguard_show_client.html:61
#: plinth/modules/wireguard/templates/wireguard_show_server.html:60
msgid "Latest handshake:"
-msgstr ""
+msgstr "Poslední handshake:"
#: plinth/modules/wireguard/templates/wireguard_show_server.html:14
#, python-format
@@ -8144,6 +8018,9 @@ msgid ""
"information. Ensure that the server is configured to allow %(box_name)s's "
"public key and IP address."
msgstr ""
+"%(box_name)s se pokusí spojit se serverem WireGuard s následujícími "
+"informacemi. Ujistěte se, že je server nakonfigurován tak, aby povolil "
+"veřejný klíč a IP adresu %(box_name)s."
#: plinth/modules/wireguard/templates/wireguard_show_server.html:24
msgid "Server endpoint:"
@@ -8151,95 +8028,67 @@ msgstr "Koncový bod serveru:"
#: plinth/modules/wireguard/templates/wireguard_show_server.html:36
msgid "Public key of this machine:"
-msgstr ""
+msgstr "Veřejný klíč tohoto stroje:"
#: plinth/modules/wireguard/templates/wireguard_show_server.html:40
msgid "IP address of this machine:"
-msgstr ""
+msgstr "IP adresa tohoto počítače:"
#: plinth/modules/wireguard/views.py:43
-#, fuzzy
-#| msgid "Add new introducer"
msgid "Added new client."
-msgstr "Přidat nový uvaděč"
+msgstr "Přidán nový klient."
#: plinth/modules/wireguard/views.py:58 plinth/modules/wireguard/views.py:117
-#, fuzzy
-#| msgid "A share with this name already exists."
msgid "Client with public key already exists"
-msgstr "Sdílení s tímto názvem už existuje."
+msgstr "Klient s veřejným klíčem již existuje"
#: plinth/modules/wireguard/views.py:71
-#, fuzzy
-#| msgid "Email Client"
msgid "Allowed Client"
-msgstr "E-mailový klient"
+msgstr "Povolený klient"
#: plinth/modules/wireguard/views.py:93
-#, fuzzy
-#| msgid "Update setup"
msgid "Updated client."
-msgstr "Aktualizovat nastavení"
+msgstr "Aktualizovaný klient."
#: plinth/modules/wireguard/views.py:98
-#, fuzzy
-#| msgid "Email Client"
msgid "Modify Client"
-msgstr "E-mailový klient"
+msgstr "Upravit klienta"
#: plinth/modules/wireguard/views.py:131
-#, fuzzy
-#| msgid "Delete All"
msgid "Delete Allowed Client"
-msgstr "Smazat vše"
+msgstr "Odstranit povoleného klienta"
#: plinth/modules/wireguard/views.py:140
-#, fuzzy
-#| msgid "Archive deleted."
msgid "Client deleted."
-msgstr "Archiv smazán."
+msgstr "Klient smazán."
#: plinth/modules/wireguard/views.py:142
-#, fuzzy
-#| msgid "Repository not found"
msgid "Client not found"
-msgstr "Repozitář nenalezen"
+msgstr "Klient nenalezen"
#: plinth/modules/wireguard/views.py:152
-#, fuzzy
-#| msgid "Added custom service"
msgid "Added new server."
-msgstr "Uživatelem určená služba přidána"
+msgstr "Přidán nový server."
#: plinth/modules/wireguard/views.py:173
-#, fuzzy
-#| msgid "Connection Type"
msgid "Connection to Server"
-msgstr "Typ připojení"
+msgstr "Připojení k serveru"
#: plinth/modules/wireguard/views.py:191
-#, fuzzy
-#| msgid "Update setup"
msgid "Updated server."
-msgstr "Aktualizovat nastavení"
+msgstr "Aktualizovaný server."
#: plinth/modules/wireguard/views.py:196
-#, fuzzy
-#| msgid "Edit Connection"
msgid "Modify Connection to Server"
-msgstr "Upravit připojení"
+msgstr "Změnit připojení k serveru"
#: plinth/modules/wireguard/views.py:233
-#, fuzzy
-#| msgid "Delete Connection"
msgid "Delete Connection to Server"
-msgstr "Smazat připojení"
+msgstr "Odstranit připojení k serveru"
#: plinth/modules/wireguard/views.py:253
-#, fuzzy
-#| msgid "Share deleted."
msgid "Server deleted."
-msgstr "Sdílení smazáno."
+msgstr "Server smazán."
#: plinth/modules/wordpress/__init__.py:23
msgid ""
@@ -8249,6 +8098,11 @@ msgid ""
"Administration interface and produced web pages are suitable for mobile "
"devices."
msgstr ""
+"WordPress je oblíbený způsob vytváření a správy webových stránek a blogů. "
+"Obsah lze spravovat pomocí vizuálního rozhraní. Rozvržení a funkčnost "
+"webových stránek lze přizpůsobit. Vzhled lze zvolit pomocí motivů. "
+"Administrační rozhraní a vytvořené webové stránky jsou vhodné pro mobilní "
+"zařízení."
#: plinth/modules/wordpress/__init__.py:29
#, python-brace-format
@@ -8258,6 +8112,10 @@ msgid ""
"the correct domain name. Enable permalinks in administrator interface for "
"better URLs to your pages and posts."
msgstr ""
+"Před zveřejněním webu níže je třeba spustit nastavení WordPressu návštěvou "
+"aplikace. Nastavení musí být spuštěno při přístupu k {box_name} se správným "
+"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
msgid ""
@@ -8265,6 +8123,10 @@ msgid ""
"during setup. Bookmark the admin page "
"to reach administration interface in the future."
msgstr ""
+"WordPress má vlastní uživatelské účty. První účet správce je vytvořen během "
+"instalace. Chcete-li se v budoucnu dostat do administračního rozhraní, "
+"přidejte si stranu administrace do "
+"záložek."
#: plinth/modules/wordpress/__init__.py:38
msgid ""
@@ -8272,31 +8134,31 @@ msgid ""
"from administrator interface. Additional plugins or themes may be installed "
"and upgraded at your own risk."
msgstr ""
+"Po aktualizaci hlavní verze je třeba spustit aktualizaci databáze ručně z "
+"rozhraní správce. Další zásuvné moduly nebo témata lze instalovat a "
+"aktualizovat na vlastní riziko."
#: plinth/modules/wordpress/__init__.py:58
#: plinth/modules/wordpress/manifest.py:6
-#, fuzzy
-#| msgid "Address"
msgid "WordPress"
-msgstr "Adresa"
+msgstr "WordPress"
#: plinth/modules/wordpress/__init__.py:59
-#, fuzzy
-#| msgid "Wiki and Blog"
msgid "Website and Blog"
-msgstr "wiki a blog"
+msgstr "Webové stránky a blog"
#: plinth/modules/wordpress/forms.py:14
-#, fuzzy
-#| msgid "public access"
msgid "Public access"
-msgstr "veřejný přístup"
+msgstr "Veřejný přístup"
#: plinth/modules/wordpress/forms.py:15
msgid ""
"Allow all visitors. Disabling allows only administrators to view the "
"WordPress site or blog. Enable only after performing initial WordPress setup."
msgstr ""
+"Povolte vstup všem návštěvníkům. Zakázání umožní prohlížení webu nebo blogu "
+"WordPress pouze správcům. Povolte pouze po provedení počátečního nastavení "
+"WordPressu."
#: plinth/modules/zoph/__init__.py:26
#, python-brace-format
@@ -8310,6 +8172,15 @@ msgid ""
"location using search, map and calendar views. Individual photos can be "
"shared with others by sending a direct link."
msgstr ""
+"Zoph spravuje vaši sbírku fotografií. Fotografie jsou uloženy ve vaší "
+"{box_name} a máte je pod kontrolou. Namísto galerií pro veřejnou prezentaci "
+"se Zoph zaměřuje na jejich správu pro vlastní potřebu a organizuje je podle "
+"toho, kdo je pořídil, kde byly pořízeny a kdo na nich je. Fotografie lze "
+"propojit do více hierarchických alb a kategorií. Pomocí vyhledávání, "
+"zobrazení mapy a kalendáře lze snadno vyhledat všechny fotografie, na nichž "
+"je zachycena určitá osoba, nebo fotografie pořízené v určitý den či na "
+"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
#, python-brace-format
@@ -8318,31 +8189,34 @@ msgid ""
"Zoph. For additional users, accounts must be created both in {box_name} and "
"in Zoph with the same user name."
msgstr ""
+"Uživatel {box_name}, který nastavil Zoph, se stane také správcem v Zoph. Pro "
+"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:58 plinth/modules/zoph/manifest.py:6
msgid "Zoph"
-msgstr ""
+msgstr "Zoph"
#: plinth/modules/zoph/__init__.py:59
msgid "Photo Organizer"
-msgstr ""
+msgstr "Organizér fotografií"
#: plinth/modules/zoph/forms.py:14
msgid "Enable OpenStreetMap for maps"
-msgstr ""
+msgstr "Povolení OpenStreetMap pro mapy"
#: plinth/modules/zoph/forms.py:15
msgid ""
"When enabled, requests will be made to OpenStreetMap servers from user's "
"browser. This impacts privacy."
msgstr ""
+"Pokud je tato funkce povolena, budou požadavky na servery OpenStreetMap "
+"odesílány z prohlížeče uživatele. To má dopad na soukromí."
#: plinth/modules/zoph/templates/zoph-pre-setup.html:15
#: plinth/modules/zoph/templates/zoph-pre-setup.html:28
-#, fuzzy
-#| msgid "Start Setup"
msgid "Setup"
-msgstr "Spustit nastavení"
+msgstr "Nastavení"
#: plinth/modules/zoph/templates/zoph-pre-setup.html:18
#, python-format
@@ -8350,6 +8224,8 @@ msgid ""
"User account %(username)s will become the administrator "
"account for Zoph."
msgstr ""
+"Uživatelský účet %(username)s se stane administrátorským "
+"účtem pro Zoph."
#: plinth/network.py:29
msgid "PPPoE"
@@ -8399,42 +8275,31 @@ msgid "Requested page %(request_path)s was not found."
msgstr "Požadovaná stránka %(request_path)s nebyla nalezena."
#: plinth/templates/404.html:19
-#, fuzzy
-#| msgid ""
-#| "If you believe this missing page should exist, please file a bug at the "
-#| "FreedomBox Service (Plinth) project issue tracker."
msgid ""
"If you believe this missing page should exist, please file a bug at the "
"FreedomBox Service (Plinth) project issue tracker."
msgstr ""
-"Pokud se domníváte, že by chybějící stránka měla existovat, nahlaste to do "
-"systému "
-"hlášení chyb projektu FreedomBox Service (Plinth)."
+"Pokud se domníváte, že by tato chybějící stránka měla existovat, nahlaste "
+"prosím chybu v projektu FreedomBox Service (Plinth) issue tracker."
#: plinth/templates/500.html:10
msgid "500"
msgstr "500"
#: plinth/templates/500.html:14
-#, fuzzy, python-format
-#| msgid ""
-#| "This is an internal error and not something you caused or can fix. Please "
-#| "report the error on the bug tracker so we can fix it. Also, please "
-#| "attach the status log to the bug "
-#| "report."
+#, python-format
msgid ""
"This is an internal error and not something you caused or can fix. Please "
"report the error on the bug tracker so we can fix it. Also, please attach "
"the status log to the bug report."
msgstr ""
-"Toto je vnitřní chyba a tedy ne něco, co jste způsobili nebo můžete opravit. "
-"Nahlaste to do systému hlášení chyb abychom to mohli opravit. K hlášení také "
-"přiložte záznam (log) stavu."
+"Jedná se o interní chybu, kterou jste nezpůsobili ani ji nemůžete opravit. "
+"Nahlaste prosím chybu na sledovači chyb, abychom ji mohli opravit. K hlášení "
+"chyby prosím připojte také status log."
#: plinth/templates/app-header.html:22
msgid "Installation"
@@ -8621,13 +8486,13 @@ msgid "Mailing list"
msgstr "Poštovní konference"
#: plinth/templates/internal-zone.html:11
-#, fuzzy, python-format
-#| msgid "%(service_name)s is available only on internal networks."
+#, python-format
msgid ""
"%(service_name)s is available only on internal networks or when the "
"client is connected to %(box_name)s through VPN."
msgstr ""
-"Služba %(service_name)s je k dispozici pouze na vnitřních sítích."
+"%(service_name)s je k dispozici pouze ve vnitřních sítích nebo když "
+"je klient připojen k %(box_name)s prostřednictvím sítě VPN."
#: plinth/templates/internal-zone.html:17
msgid "Currently there are no network interfaces configured as internal."
@@ -8644,29 +8509,24 @@ msgstr ""
#: plinth/templates/messages.html:11
msgid "Close"
-msgstr ""
+msgstr "Zavřít"
#: plinth/templates/notifications-dropdown.html:11
-#, fuzzy
-#| msgid "No certificate"
msgid "Notifications"
-msgstr "Žádný certifikát"
+msgstr "Oznámení"
#: plinth/templates/port-forwarding-info.html:8
msgid "Port Forwarding"
msgstr "Předávání portů"
#: plinth/templates/port-forwarding-info.html:13
-#, fuzzy, python-format
-#| msgid ""
-#| "You may want to check the network setup "
-#| "and modify it if necessary."
+#, python-format
msgid ""
"Your FreedomBox is not behind a router. No "
"action is necessary."
msgstr ""
-"Možná bude třeba zkontrolovat nastavení sítě"
-"a> a případně upravit."
+"Váš FreedomBox není za routerem. Není třeba "
+"provádět žádné akce."
#: plinth/templates/port-forwarding-info.html:19
#, python-format
@@ -8675,37 +8535,33 @@ msgid ""
"are using the DMZ feature to forward all ports. No further router "
"configuration is necessary."
msgstr ""
+"Váš FreedomBox je za směrovačem a používáte "
+"funkci DMZ pro přesměrování všech portů. Žádná další konfigurace směrovače "
+"není nutná."
#: plinth/templates/port-forwarding-info.html:26
-#, fuzzy, python-format
-#| msgid ""
-#| "If your FreedomBox is behind a router, you will need to set up port "
-#| "forwarding on your router. You should forward the following ports for "
-#| "%(service_name)s:"
+#, python-format
msgid ""
"Your FreedomBox is behind a router and you "
"are not using the DMZ feature. You will need to set up port forwarding on "
"your router. You should forward the following ports for %(service_name)s:"
msgstr ""
-"Pokud se váš FreedomBox nachází za směrovačem, bude třeba na směrovači "
-"nastavit předávání portů. Přesměrovávány by měly být následující porty pro "
-"%(service_name)s:"
+"Váš FreedomBox je za routerem a nepoužíváte "
+"funkci DMZ. Budete muset na svém směrovači nastavit přesměrování portů. Měli "
+"byste přesměrovat následující porty pro %(service_name)s:"
#: plinth/templates/port-forwarding-info.html:37
-#, fuzzy
-#| msgid "protocol"
msgid "Protocol"
msgstr "protokol"
#: plinth/templates/port-forwarding-info.html:38
msgid "From Router/WAN Ports"
-msgstr ""
+msgstr "Z portů směrovače/sítě LAN"
#: plinth/templates/port-forwarding-info.html:39
-#, fuzzy, python-format
-#| msgid "%(box_name)s Setup"
+#, python-format
msgid "To %(box_name)s Ports"
-msgstr "Nastavení %(box_name)s"
+msgstr "Na %(box_name)s Porty"
#: plinth/templates/setup.html:24
msgid "Install this application?"
@@ -8731,7 +8587,7 @@ msgstr ""
#: plinth/templates/setup.html:50
msgid "Check again"
-msgstr ""
+msgstr "Znovu zkontrolovat"
#: plinth/templates/setup.html:55
msgid ""
@@ -8739,10 +8595,13 @@ msgid ""
"conflict with the installation of this app. The following packages will be "
"removed if you proceed:"
msgstr ""
+"Konfliktní balíčky: Některé balíčky nainstalované v systému "
+"jsou v konfliktu s instalací této aplikace. Následující balíčky budou v "
+"případě pokračování odstraněny:"
#: plinth/templates/setup.html:71
msgid "Install"
-msgstr "Nainstalovat"
+msgstr "Instalace"
#: plinth/templates/setup.html:83
msgid "Performing pre-install operation"
From 41f5ccd80c01ccc2b5a099c888ec98bfa8153063 Mon Sep 17 00:00:00 2001
From: pesder
Date: Sun, 19 Dec 2021 00:10:58 +0000
Subject: [PATCH 22/32] Translated using Weblate (Chinese (Traditional))
Currently translated at 17.2% (259 of 1498 strings)
---
plinth/locale/zh_Hant/LC_MESSAGES/django.po | 30 ++++++++++++---------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/plinth/locale/zh_Hant/LC_MESSAGES/django.po b/plinth/locale/zh_Hant/LC_MESSAGES/django.po
index 11ed56468..bcec58d3e 100644
--- a/plinth/locale/zh_Hant/LC_MESSAGES/django.po
+++ b/plinth/locale/zh_Hant/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-06 18:35-0500\n"
-"PO-Revision-Date: 2021-12-18 21:57+0000\n"
+"PO-Revision-Date: 2021-12-20 13:51+0000\n"
"Last-Translator: pesder \n"
"Language-Team: Chinese (Traditional) \n"
@@ -1249,15 +1249,15 @@ msgstr "網頁伺服器首頁設定"
#: plinth/modules/config/views.py:80
#, python-brace-format
msgid "Error changing advanced mode: {exception}"
-msgstr ""
+msgstr "改變進階模式時發生錯誤︰{exception}"
#: plinth/modules/config/views.py:85
msgid "Showing advanced apps and features"
-msgstr ""
+msgstr "顯示進階 app 與功能"
#: plinth/modules/config/views.py:88
msgid "Hiding advanced apps and features"
-msgstr ""
+msgstr "隱藏進階 app 與功能"
#: plinth/modules/coturn/__init__.py:29
msgid ""
@@ -1266,6 +1266,8 @@ msgid ""
"other communication servers can use it to establish a call between parties "
"who are otherwise unable connect to each other."
msgstr ""
+"Coturn 是一個伺服器,通過提供 TURN 和 STUN 通訊協定的實作來促進音訊/視訊通話和會議。 WebRTC、SIP "
+"和其他通訊伺服器可以使用它在無法相互連接的各方之間建立通訊。"
#: plinth/modules/coturn/__init__.py:34
#, python-brace-format
@@ -1274,40 +1276,42 @@ msgid ""
"\"{ms_url}\">Matrix Synapse or ejabberd need to "
"be configured with the details provided here."
msgstr ""
+"這不是讓使用者直接使用的。伺服器如 Matrix Synapse 或 ejabberd 都需要以在這裡提供的資料來設定。"
#: plinth/modules/coturn/__init__.py:57
msgid "Coturn"
-msgstr ""
+msgstr "Coturn"
#: plinth/modules/coturn/__init__.py:58
msgid "VoIP Helper"
-msgstr ""
+msgstr "VoIP 協助程式"
#: plinth/modules/coturn/forms.py:22
msgid "Invalid list of STUN/TURN Server URIs"
-msgstr ""
+msgstr "STUN/TURN 伺服器 URI 列表無效"
#: plinth/modules/coturn/templates/coturn.html:15
msgid "Use the following URLs to configure your communication server:"
-msgstr ""
+msgstr "使用下列 URL 來設定您的通訊伺服器︰"
#: plinth/modules/coturn/templates/coturn.html:24
msgid "Use the following shared authentication secret:"
-msgstr ""
+msgstr "使用下列分享核對金鑰:"
#: plinth/modules/datetime/__init__.py:18
msgid ""
"Network time server is a program that maintains the system time in "
"synchronization with servers on the Internet."
-msgstr ""
+msgstr "網路時刻伺服器是一種透過網際網路與伺服器同步以維護系統時刻的程式。"
#: plinth/modules/datetime/__init__.py:64
msgid "Date & Time"
-msgstr ""
+msgstr "日期 & 時刻"
#: plinth/modules/datetime/__init__.py:110
msgid "Time synchronized to NTP server"
-msgstr ""
+msgstr "時刻與 NTP 伺服器同步"
#: plinth/modules/datetime/forms.py:18
msgid "Time Zone"
@@ -1317,7 +1321,7 @@ msgstr "時區"
msgid ""
"Set your time zone to get accurate timestamps. This will set the system-wide "
"time zone."
-msgstr ""
+msgstr "設定您的時區以取得正確的時刻戳記。這會設定系統層級的時區。"
#: plinth/modules/datetime/forms.py:30
msgid "-- no time zone set --"
From 690859b02feea8f0c2045ed4de410c9d13124352 Mon Sep 17 00:00:00 2001
From: James Valleroy
Date: Sat, 11 Dec 2021 20:59:29 -0500
Subject: [PATCH 23/32] upgrades: Refactor dist upgrade process
No change in functionality.
Signed-off-by: James Valleroy
[sunil: Fix copy/paste error with indentation in start_dist_upgrade_service]
Signed-off-by: Sunil Mohan Adapa
Reviewed-by: Sunil Mohan Adapa
---
actions/upgrades | 183 +++++++++++++++++++++++++++++++----------------
1 file changed, 122 insertions(+), 61 deletions(-)
diff --git a/actions/upgrades b/actions/upgrades
index 6abcaad9d..0cd46cbdc 100755
--- a/actions/upgrades
+++ b/actions/upgrades
@@ -89,6 +89,26 @@ Pin: release a=buster-backports
Pin-Priority: 500
'''
+DIST_UPGRADE_OBSOLETE_PACKAGES = ['libgcc1']
+
+DIST_UPGRADE_PACKAGES_WITH_PROMPTS = [
+ 'firewalld', 'mumble-server', 'radicale', 'roundcube-core'
+]
+
+# These are packages that may not be available in the next stable release.
+DIST_UPGRADE_OPTIONAL_PACKAGES_WITH_PROMPTS = ['tt-rss']
+
+DIST_UPGRADE_PRE_INSTALL_PACKAGES = [
+ 'base-files', 'python3-systemd', 'unattended-upgrades'
+]
+
+DIST_UPGRADE_PRE_DEBCONF_SELECTIONS = [
+ # Tell grub-pc to continue without installing grub again.
+ 'grub-pc grub-pc/install_devices_empty boolean true'
+]
+
+DIST_UPGRADE_REQUIRED_FREE_SPACE = 5000000
+
DIST_UPGRADE_SERVICE = '''
[Unit]
Description=Upgrade to new stable Debian release
@@ -138,15 +158,18 @@ def parse_arguments():
return parser.parse_args()
+def _release_held_freedombox():
+ """In case freedombox package was left in held state by an interrupted
+ process, release it."""
+ if apt_hold_flag.exists() and not is_package_manager_busy():
+ apt_unhold_freedombox()
+
+
def _run():
"""Run unattended-upgrades"""
subprocess.run(['dpkg', '--configure', '-a'], check=False)
run_apt_command(['--fix-broken', 'install'])
-
- # In case freedombox package was left in held state by an
- # interrupted process, release it.
- if apt_hold_flag.exists() and not is_package_manager_busy():
- apt_unhold_freedombox()
+ _release_held_freedombox()
subprocess.Popen(['systemctl', 'start', 'freedombox-manual-upgrade'],
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
@@ -326,6 +349,13 @@ def _add_apt_preferences():
file_handle.write(APT_PREFERENCES_APPS)
+def _is_sufficient_free_space():
+ """Return whether there is sufficient free space for dist upgrade."""
+ output = subprocess.check_output(['df', '--output=avail', '/'])
+ free_space = int(output.decode().split('\n')[1])
+ return free_space >= DIST_UPGRADE_REQUIRED_FREE_SPACE
+
+
def _check_dist_upgrade(test_upgrade=False):
"""Check for new stable release, if updates are enabled, and if there is
enough free space for the dist upgrade.
@@ -377,9 +407,7 @@ def _check_dist_upgrade(test_upgrade=False):
if check_dist == 'testing' and not test_upgrade:
return (False, 'test-not-set')
- output = subprocess.check_output(['df', '--output=avail', '/'])
- free_space = int(output.decode().split('\n')[1])
- if free_space < 5000000:
+ if not _is_sufficient_free_space():
return (False, 'not-enough-free-space')
logging.info('Upgrading from %s to %s...', dist, codename)
@@ -405,29 +433,44 @@ def _check_dist_upgrade(test_upgrade=False):
return (True, 'started-dist-upgrade')
-def _perform_dist_upgrade():
- """Perform upgrade to next release of Debian."""
- # Take a snapshot if supported and enabled, then disable snapshots.
- snapshots_supported = snapshot_is_supported()
- if snapshots_supported:
+def _take_snapshot_and_disable():
+ """Take a snapshot if supported and enabled, then disable snapshots.
+
+ 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)
aug = snapshot_load_augeas()
- apt_snapshots_enabled = is_apt_snapshots_enabled(aug)
- if apt_snapshots_enabled:
+ 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)
+ return True
else:
print('Apt snapshots already disabled.', flush=True)
else:
print('Snapshots are not supported, skip taking a snapshot.',
flush=True)
- # If searx is enabled, disable it until we can upgrade it properly.
+ return False
+
+
+def _restore_snapshots_config(reenable):
+ """Restore original snapshots configuration."""
+ if reenable:
+ print('Re-enable apt snapshots...', flush=True)
+ subprocess.run([
+ '/usr/share/plinth/actions/snapshot', 'disable-apt-snapshot', 'no'
+ ], check=True)
+
+
+def _disable_searx():
+ """If searx is enabled, disable it until we can upgrade it properly.
+
+ Return whether searx was originally enabled."""
searx_is_enabled = pathlib.Path(
'/etc/uwsgi/apps-enabled/searx.ini').exists()
if searx_is_enabled:
@@ -437,54 +480,75 @@ def _perform_dist_upgrade():
'searx'
], check=True)
+ return searx_is_enabled
+
+
+def _update_searx(reenable):
+ """If searx is installed, update search engines list.
+ 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)
+ if reenable:
+ print('Re-enabling searx after upgrade...', flush=True)
+ subprocess.run([
+ '/usr/share/plinth/actions/apache', 'uwsgi-enable', '--name',
+ 'searx'
+ ], check=True)
+
+
+def _perform_dist_upgrade():
+ """Perform upgrade to next release of Debian."""
+ reenable_snapshots = _take_snapshot_and_disable()
+ reenable_searx = _disable_searx()
+
# Hold freedombox package during entire dist upgrade.
print('Holding freedombox package...', flush=True)
with apt_hold_freedombox():
print('Updating Apt cache...', flush=True)
run_apt_command(['update'])
- print('Upgrading base-files and unattended-upgrades...', flush=True)
- run_apt_command(['install', 'base-files'])
- run_apt_command(['install', 'python3-systemd', 'unattended-upgrades'])
+ # Install packages that are necessary for unattended-upgrades
+ # to start the dist upgrade.
+ print(f'Upgrading packages: {DIST_UPGRADE_PRE_INSTALL_PACKAGES}...',
+ flush=True)
+ run_apt_command(['install'] + DIST_UPGRADE_PRE_INSTALL_PACKAGES)
- # Tell grub-pc to continue without installing grub again.
- print('Set grub-pc to not require re-installing grub...', flush=True)
- debconf_set_selections(
- ['grub-pc grub-pc/install_devices_empty boolean true'])
+ # Pre-set debconf selections if they are required during the
+ # dist upgrade.
+ print(
+ f'Setting debconf selections: '
+ f'{DIST_UPGRADE_PRE_DEBCONF_SELECTIONS}', flush=True)
+ debconf_set_selections(DIST_UPGRADE_PRE_DEBCONF_SELECTIONS)
+ # This will upgrade most of the packages.
print('Running unattended-upgrade...', flush=True)
subprocess.run(['unattended-upgrade', '--verbose'], check=False)
# Remove obsolete packages that may prevent other packages from
# upgrading.
- print('Removing libgcc1...', flush=True)
- run_apt_command(['remove', 'libgcc1'])
+ print(f'Removing packages: {DIST_UPGRADE_OBSOLETE_PACKAGES}...',
+ flush=True)
+ run_apt_command(['remove'] + DIST_UPGRADE_OBSOLETE_PACKAGES)
# Hold packages known to have conffile prompts. FreedomBox service
# will handle their upgrade later.
- packages_with_prompts = [
- 'firewalld', 'mumble-server', 'radicale', 'roundcube-core'
- ]
print(
'Holding packages with conffile prompts: ' +
- ', '.join(packages_with_prompts) + '...', flush=True)
- with apt_hold(packages_with_prompts):
- print('Holding tt-rss package if available...', flush=True)
- with apt_hold(['tt-rss'], ignore_errors=True):
+ ', '.join(DIST_UPGRADE_PACKAGES_WITH_PROMPTS) + '...', flush=True)
+ with apt_hold(DIST_UPGRADE_PACKAGES_WITH_PROMPTS):
+ # TODO: Support holding more than 1 package here.
+ print(
+ f'Holding packages if available: '
+ f'{DIST_UPGRADE_OPTIONAL_PACKAGES_WITH_PROMPTS[0]}...',
+ flush=True)
+ with apt_hold([DIST_UPGRADE_OPTIONAL_PACKAGES_WITH_PROMPTS[0]],
+ ignore_errors=True):
print('Running apt full-upgrade...', flush=True)
run_apt_command(['full-upgrade'])
- # If searx is installed, update search engines list.
- 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)
- if searx_is_enabled:
- print('Re-enabling searx after upgrade...', flush=True)
- subprocess.run([
- '/usr/share/plinth/actions/apache', 'uwsgi-enable',
- '--name', 'searx'
- ], check=True)
+ _update_searx(reenable_searx)
print('Running apt autoremove...', flush=True)
run_apt_command(['autoremove'])
@@ -494,12 +558,7 @@ def _perform_dist_upgrade():
print('Running unattended-upgrade...', flush=True)
subprocess.run(['unattended-upgrade', '--verbose'], check=False)
- # Restore original snapshots configuration.
- if snapshots_supported and apt_snapshots_enabled:
- print('Re-enable apt snapshots...', flush=True)
- subprocess.run([
- '/usr/share/plinth/actions/snapshot', 'disable-apt-snapshot', 'no'
- ], check=True)
+ _restore_snapshots_config(reenable_snapshots)
# Restart FreedomBox service to ensure it is using the latest
# dependencies.
@@ -532,27 +591,29 @@ def subcommand_activate_backports(arguments):
_check_and_backports_sources(arguments.develop)
+def _start_dist_upgrade_service():
+ """Create dist upgrade service and start it."""
+ with open(DIST_UPGRADE_SERVICE_PATH, 'w') as service_file:
+ service_file.write(DIST_UPGRADE_SERVICE)
+
+ service_daemon_reload()
+ subprocess.Popen(['systemctl', 'start', 'freedombox-dist-upgrade'],
+ stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL, close_fds=True,
+ start_new_session=True)
+
+
def subcommand_start_dist_upgrade(arguments):
"""Start dist upgrade process.
Check if a new stable release is available, and start dist-upgrade process
if updates are enabled.
"""
- # In case freedombox package was left in held state by an
- # interrupted process, release it.
- if apt_hold_flag.exists() and not is_package_manager_busy():
- apt_unhold_freedombox()
+ _release_held_freedombox()
upgrade_ready, reason = _check_dist_upgrade(arguments.test)
if upgrade_ready:
- with open(DIST_UPGRADE_SERVICE_PATH, 'w') as service_file:
- service_file.write(DIST_UPGRADE_SERVICE)
-
- service_daemon_reload()
- subprocess.Popen(['systemctl', 'start', 'freedombox-dist-upgrade'],
- stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL, close_fds=True,
- start_new_session=True)
+ _start_dist_upgrade_service()
print(
json.dumps({
From 32d9f01597ecf97a15d069c9752ce2f11c5c9bb4 Mon Sep 17 00:00:00 2001
From: James Valleroy
Date: Sun, 12 Dec 2021 17:19:37 -0500
Subject: [PATCH 24/32] upgrades: Cleanup dist upgrade steps specific to
bullseye release
- Skip handling of obsolete packages if there are none.
- Skip handling of debconf selections if none are required.
- Handle tt-rss same as other packages with prompts.
Signed-off-by: James Valleroy
Reviewed-by: Sunil Mohan Adapa
---
actions/upgrades | 47 +++++++++++++++++++----------------------------
1 file changed, 19 insertions(+), 28 deletions(-)
diff --git a/actions/upgrades b/actions/upgrades
index 0cd46cbdc..fce151963 100755
--- a/actions/upgrades
+++ b/actions/upgrades
@@ -89,23 +89,15 @@ Pin: release a=buster-backports
Pin-Priority: 500
'''
-DIST_UPGRADE_OBSOLETE_PACKAGES = ['libgcc1']
+DIST_UPGRADE_OBSOLETE_PACKAGES = []
DIST_UPGRADE_PACKAGES_WITH_PROMPTS = [
- 'firewalld', 'mumble-server', 'radicale', 'roundcube-core'
+ 'firewalld', 'mumble-server', 'radicale', 'roundcube-core', 'tt-rss'
]
-# These are packages that may not be available in the next stable release.
-DIST_UPGRADE_OPTIONAL_PACKAGES_WITH_PROMPTS = ['tt-rss']
+DIST_UPGRADE_PRE_INSTALL_PACKAGES = ['base-files']
-DIST_UPGRADE_PRE_INSTALL_PACKAGES = [
- 'base-files', 'python3-systemd', 'unattended-upgrades'
-]
-
-DIST_UPGRADE_PRE_DEBCONF_SELECTIONS = [
- # Tell grub-pc to continue without installing grub again.
- 'grub-pc grub-pc/install_devices_empty boolean true'
-]
+DIST_UPGRADE_PRE_DEBCONF_SELECTIONS = []
DIST_UPGRADE_REQUIRED_FREE_SPACE = 5000000
@@ -517,10 +509,11 @@ def _perform_dist_upgrade():
# Pre-set debconf selections if they are required during the
# dist upgrade.
- print(
- f'Setting debconf selections: '
- f'{DIST_UPGRADE_PRE_DEBCONF_SELECTIONS}', flush=True)
- debconf_set_selections(DIST_UPGRADE_PRE_DEBCONF_SELECTIONS)
+ if DIST_UPGRADE_PRE_DEBCONF_SELECTIONS:
+ print(
+ f'Setting debconf selections: '
+ f'{DIST_UPGRADE_PRE_DEBCONF_SELECTIONS}', flush=True)
+ debconf_set_selections(DIST_UPGRADE_PRE_DEBCONF_SELECTIONS)
# This will upgrade most of the packages.
print('Running unattended-upgrade...', flush=True)
@@ -528,25 +521,23 @@ def _perform_dist_upgrade():
# Remove obsolete packages that may prevent other packages from
# upgrading.
- print(f'Removing packages: {DIST_UPGRADE_OBSOLETE_PACKAGES}...',
- flush=True)
- run_apt_command(['remove'] + DIST_UPGRADE_OBSOLETE_PACKAGES)
+ if DIST_UPGRADE_OBSOLETE_PACKAGES:
+ print(f'Removing packages: {DIST_UPGRADE_OBSOLETE_PACKAGES}...',
+ flush=True)
+ run_apt_command(['remove'] + DIST_UPGRADE_OBSOLETE_PACKAGES)
# Hold packages known to have conffile prompts. FreedomBox service
# will handle their upgrade later.
print(
'Holding packages with conffile prompts: ' +
', '.join(DIST_UPGRADE_PACKAGES_WITH_PROMPTS) + '...', flush=True)
+ # XXX: If any of these packages have been removed from the
+ # next stable release, they will causes the hold command to
+ # fail for all packages. So it would be safer to just hold one
+ # package at a time.
with apt_hold(DIST_UPGRADE_PACKAGES_WITH_PROMPTS):
- # TODO: Support holding more than 1 package here.
- print(
- f'Holding packages if available: '
- f'{DIST_UPGRADE_OPTIONAL_PACKAGES_WITH_PROMPTS[0]}...',
- flush=True)
- with apt_hold([DIST_UPGRADE_OPTIONAL_PACKAGES_WITH_PROMPTS[0]],
- ignore_errors=True):
- print('Running apt full-upgrade...', flush=True)
- run_apt_command(['full-upgrade'])
+ print('Running apt full-upgrade...', flush=True)
+ run_apt_command(['full-upgrade'])
_update_searx(reenable_searx)
From f72505d300ff2e722793d2c1601b6d46a2c1ac5f Mon Sep 17 00:00:00 2001
From: James Valleroy
Date: Mon, 13 Dec 2021 09:21:08 -0500
Subject: [PATCH 25/32] upgrades: Add type annotations to action
Signed-off-by: James Valleroy
Reviewed-by: Sunil Mohan Adapa
---
actions/upgrades | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/actions/upgrades b/actions/upgrades
index fce151963..9b5720c37 100755
--- a/actions/upgrades
+++ b/actions/upgrades
@@ -13,6 +13,7 @@ import re
import subprocess
import sys
import time
+from typing import List, Tuple
from plinth.action_utils import (apt_hold, apt_hold_flag, apt_hold_freedombox,
apt_unhold_freedombox, debconf_set_selections,
@@ -89,7 +90,7 @@ Pin: release a=buster-backports
Pin-Priority: 500
'''
-DIST_UPGRADE_OBSOLETE_PACKAGES = []
+DIST_UPGRADE_OBSOLETE_PACKAGES: List[str] = []
DIST_UPGRADE_PACKAGES_WITH_PROMPTS = [
'firewalld', 'mumble-server', 'radicale', 'roundcube-core', 'tt-rss'
@@ -97,7 +98,7 @@ DIST_UPGRADE_PACKAGES_WITH_PROMPTS = [
DIST_UPGRADE_PRE_INSTALL_PACKAGES = ['base-files']
-DIST_UPGRADE_PRE_DEBCONF_SELECTIONS = []
+DIST_UPGRADE_PRE_DEBCONF_SELECTIONS: List[str] = []
DIST_UPGRADE_REQUIRED_FREE_SPACE = 5000000
@@ -181,7 +182,7 @@ def subcommand_run(_):
sys.exit(3)
-def _check_auto():
+def _check_auto() -> bool:
"""Check if automatic upgrades are enabled."""
arguments = [
'apt-config', 'shell', 'UpdateInterval',
@@ -236,7 +237,7 @@ def subcommand_get_log(_):
pass
-def _get_protocol():
+def _get_protocol() -> str:
"""Return the protocol to use for newly added repository sources."""
try:
from plinth.modules.tor import utils
@@ -248,7 +249,8 @@ def _get_protocol():
return 'http'
-def _is_release_file_available(protocol, dist, backports=False):
+def _is_release_file_available(protocol: str, dist: str,
+ backports=False) -> bool:
"""Return whether the release for dist[-backports] is available."""
wrapper = None
if protocol == 'tor+http':
@@ -261,7 +263,7 @@ def _is_release_file_available(protocol, dist, backports=False):
return result == 'passed'
-def _add_backports_sources(sources_list, protocol, dist):
+def _add_backports_sources(sources_list: str, protocol: str, dist: str):
"""Add backports sources to freedombox repositories list."""
sources = '''# This file is managed by FreedomBox, do not edit.
# Allow carefully selected updates to 'freedombox' from backports.
@@ -341,14 +343,14 @@ def _add_apt_preferences():
file_handle.write(APT_PREFERENCES_APPS)
-def _is_sufficient_free_space():
+def _is_sufficient_free_space() -> bool:
"""Return whether there is sufficient free space for dist upgrade."""
output = subprocess.check_output(['df', '--output=avail', '/'])
free_space = int(output.decode().split('\n')[1])
return free_space >= DIST_UPGRADE_REQUIRED_FREE_SPACE
-def _check_dist_upgrade(test_upgrade=False):
+def _check_dist_upgrade(test_upgrade=False) -> Tuple[bool, str]:
"""Check for new stable release, if updates are enabled, and if there is
enough free space for the dist upgrade.
@@ -425,7 +427,7 @@ def _check_dist_upgrade(test_upgrade=False):
return (True, 'started-dist-upgrade')
-def _take_snapshot_and_disable():
+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."""
@@ -450,7 +452,7 @@ def _take_snapshot_and_disable():
return False
-def _restore_snapshots_config(reenable):
+def _restore_snapshots_config(reenable=False):
"""Restore original snapshots configuration."""
if reenable:
print('Re-enable apt snapshots...', flush=True)
@@ -459,7 +461,7 @@ def _restore_snapshots_config(reenable):
], check=True)
-def _disable_searx():
+def _disable_searx() -> bool:
"""If searx is enabled, disable it until we can upgrade it properly.
Return whether searx was originally enabled."""
@@ -475,7 +477,7 @@ def _disable_searx():
return searx_is_enabled
-def _update_searx(reenable):
+def _update_searx(reenable=False):
"""If searx is installed, update search engines list.
Re-enable if previously enabled."""
if pathlib.Path('/etc/searx/settings.yml').exists():
From ce5274d9ee3bc52a3cb5a00cf3d6b7cfeaa1be59 Mon Sep 17 00:00:00 2001
From: Joseph Nuthalapati
Date: Sat, 11 Dec 2021 11:50:09 +0530
Subject: [PATCH 26/32] monkeysphere: Drop app as it is not being used
Closes #2157.
Signed-off-by: Joseph Nuthalapati
[sunil: Split diaspora and tahoe-lafs into separate commits]
[sunil: Remove monkeysphere from help/tests/test_views.py]
[sunil: Add to configuration file removal in Debian package and setup.py]
Signed-off-by: Sunil Mohan Adapa
Reviewed-by: Sunil Mohan Adapa
---
actions/monkeysphere | 318 ------------------
debian/freedombox.maintscript | 1 +
plinth/modules/help/tests/test_views.py | 21 +-
plinth/modules/monkeysphere/__init__.py | 74 ----
.../etc/plinth/modules-enabled/monkeysphere | 1 -
plinth/modules/monkeysphere/manifest.py | 13 -
.../monkeysphere/static/monkeysphere.css | 20 --
.../monkeysphere/templates/monkeysphere.html | 136 --------
.../templates/monkeysphere_details.html | 85 -----
plinth/modules/monkeysphere/tests/__init__.py | 0
.../monkeysphere/tests/test_functional.py | 100 ------
plinth/modules/monkeysphere/urls.py | 19 --
plinth/modules/monkeysphere/views.py | 135 --------
plinth/tests/functional/__init__.py | 6 +-
pyproject.toml | 1 -
setup.py | 1 +
16 files changed, 15 insertions(+), 916 deletions(-)
delete mode 100755 actions/monkeysphere
delete mode 100644 plinth/modules/monkeysphere/__init__.py
delete mode 100644 plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere
delete mode 100644 plinth/modules/monkeysphere/manifest.py
delete mode 100644 plinth/modules/monkeysphere/static/monkeysphere.css
delete mode 100644 plinth/modules/monkeysphere/templates/monkeysphere.html
delete mode 100644 plinth/modules/monkeysphere/templates/monkeysphere_details.html
delete mode 100644 plinth/modules/monkeysphere/tests/__init__.py
delete mode 100644 plinth/modules/monkeysphere/tests/test_functional.py
delete mode 100644 plinth/modules/monkeysphere/urls.py
delete mode 100644 plinth/modules/monkeysphere/views.py
diff --git a/actions/monkeysphere b/actions/monkeysphere
deleted file mode 100755
index e9c892a7e..000000000
--- a/actions/monkeysphere
+++ /dev/null
@@ -1,318 +0,0 @@
-#!/usr/bin/python3
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Configuration helper for monkeysphere.
-"""
-
-import argparse
-import contextlib
-import copy
-import json
-import os
-import re
-import shutil
-import signal
-import subprocess
-import tempfile
-
-import augeas
-import psutil
-
-
-def parse_arguments():
- """Return parsed command line arguments as dictionary."""
- parser = argparse.ArgumentParser()
- subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
-
- host_show_keys = subparsers.add_parser(
- 'host-show-keys', help='Show imported/importable keys')
- host_show_keys.add_argument('key_id', nargs='?',
- help='Optional KEYID to retrieve details for')
-
- host_import_key = subparsers.add_parser(
- 'host-import-key', help='Import a key into monkeysphere')
- host_import_key.add_argument('ssh_fingerprint',
- help='SSH fingerprint of the key to import')
- host_import_key.add_argument('domains', nargs='*',
- help='List of available domains')
-
- host_publish_key = subparsers.add_parser('host-publish-key',
- help='Push host key to keyserver')
- host_publish_key.add_argument('key_ids', nargs='*',
- help='Optional list of KEYIDs')
-
- host_cancel_publish = subparsers.add_parser(
- 'host-cancel-publish', help='Cancel a running publish operation')
- host_cancel_publish.add_argument('pid', help='PID of the publish process')
-
- subparsers.required = True
- return parser.parse_args()
-
-
-def get_ssh_keys(fingerprint_hash):
- """Return all SSH keys."""
- keys = {}
-
- key_files = ['/etc/ssh/ssh_host_rsa_key']
- for key_file in key_files:
- output = subprocess.check_output(
- ['ssh-keygen', '-l', '-E', fingerprint_hash, '-f', key_file])
- fingerprint = output.decode().split()[1]
- keys[fingerprint] = {
- 'ssh_fingerprint': fingerprint,
- 'service': 'ssh',
- 'key_file': key_file,
- 'available_domains': ['*']
- }
-
- return keys
-
-
-def get_pem_ssh_fingerprint(pem_file, fingerprint_hash):
- """Return the SSH fingerprint of a PEM file."""
- public_key = subprocess.check_output(
- ['openssl', 'rsa', '-in', pem_file, '-pubout'],
- stderr=subprocess.DEVNULL)
- ssh_public_key = subprocess.check_output(
- ['ssh-keygen', '-i', '-m', 'PKCS8', '-f', '/dev/stdin'],
- input=public_key)
- fingerprint = subprocess.check_output(
- ['ssh-keygen', '-l', '-E', fingerprint_hash, '-f', '/dev/stdin'],
- input=ssh_public_key)
-
- return fingerprint.decode().split()[1]
-
-
-def get_https_keys(fingerprint_hash):
- """Return all HTTPS keys."""
- 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]',
- '/etc/apache2/sites-available/*')
- aug.set('/augeas/load/Httpd/incl[last() + 1]',
- '/etc/apache2/conf-available/*')
- aug.load()
-
- # Read from default-tls.conf and default-ssl.conf
- keys = {}
- path = '/files/etc/apache2/sites-available//VirtualHost'
- for match in aug.match(path):
- host = {'available_domains': ['*'], 'service': 'https'}
- for directive in aug.match(match + '/directive'):
- name = aug.get(directive)
- if name == 'ServerName':
- host['available_domains'] = [aug.get(directive + '/arg')]
- elif name in ('GnuTLSKeyFile', 'SSLCertificateKeyFile'):
- host['key_file'] = aug.get(directive + '/arg')
-
- if 'key_file' in host:
- host['ssh_fingerprint'] = get_pem_ssh_fingerprint(
- host['key_file'], fingerprint_hash)
- keys[host['ssh_fingerprint']] = host
-
- # Read from FreedomBox configured domains with proper SSL certs.
- path = "/files/etc/apache2/sites-available//" \
- "directive[. = 'Use'][arg[1] = 'FreedomBoxTLSSiteMacro']"
- key_file = ("/files/etc/apache2//Macro[arg[1] = 'FreedomBoxTLSSiteMacro']"
- "//VirtualHost/directive[. = 'GnuTLSKeyFile']/arg")
- key_file = aug.get(key_file)
- for match in aug.match(path):
- domain = aug.get(match + '/arg[2]')
- host = {
- 'available_domains': [domain],
- 'service': 'https',
- 'key_file': key_file.replace('$domain', domain)
- }
- host['ssh_fingerprint'] = get_pem_ssh_fingerprint(
- host['key_file'], fingerprint_hash)
- keys[host['ssh_fingerprint']] = host
-
- return keys
-
-
-def get_monkeysphere_keys(key_id=None):
- """Return the list of keys imported into monkeysphere."""
- try:
- key_ids = [] if not key_id else [key_id]
- output = subprocess.check_output(['monkeysphere-host', 'show-keys'] +
- key_ids, stderr=subprocess.DEVNULL)
- except subprocess.CalledProcessError:
- # no keys available
- return {}
-
- # parse output
- default_dict = {'imported_domains': [], 'available_domains': []}
- keys = [copy.deepcopy(default_dict)]
- lines = output.decode().strip().split('\n')
- for line in lines:
- if line.startswith('pub'):
- data = line.lstrip('pub').split()
- keys[-1]['pub'] = data[0]
- keys[-1]['date'] = data[1]
- elif line.startswith('uid'):
- uid = line.lstrip('uid').strip()
- if uid.startswith('['):
- uid = uid[uid.index(']') + 1:].strip()
-
- keys[-1].setdefault('uids', []).append(uid)
- matches = re.match(r'([a-zA-Z]*)://(.*)(:\d*)?', uid)
- keys[-1]['service'] = matches.group(1)
- keys[-1]['imported_domains'].append(matches.group(2))
- elif line.startswith('OpenPGP fingerprint:'):
- keys[-1]['openpgp_fingerprint'] = \
- line.lstrip('OpenPGP fingerprint:')
- elif line.startswith('ssh fingerprint:'):
- data = line.lstrip('ssh fingerprint:').split()
- keys[-1]['ssh_key_size'] = data[0]
- keys[-1]['ssh_fingerprint'] = data[1]
- keys[-1]['ssh_key_type'] = data[2].strip('()')
- elif line == '':
- keys.append(copy.deepcopy(default_dict))
-
- return {key['ssh_fingerprint']: key for key in keys}
-
-
-def get_merged_keys(key_id=None):
- """Return merged list of system and monkeysphere keys."""
- keys = get_monkeysphere_keys(key_id)
-
- # Monkeysphere used use MD5 for fingerprint hash and recently
- # changed to SHA256. In case of SHA256 the string 'SHA256:' is
- # being prepended to the fingerprint. Hoping that such a prefix
- # will be available in all future changes, extract it from one key
- # (assuming all the others will be the same) and use it.
- fingerprint_hash = 'SHA256'
- if keys:
- fingerprint_hash = list(keys.keys())[0].split(':')[0]
-
- system_keys = list(get_ssh_keys(fingerprint_hash).items()) + \
- list(get_https_keys(fingerprint_hash).items())
- for ssh_fingerprint, key in system_keys:
- if key_id and ssh_fingerprint not in keys:
- continue
-
- if ssh_fingerprint in keys:
- keys[ssh_fingerprint].update({
- 'available_domains': key['available_domains'],
- 'key_file': key['key_file']
- })
- else:
- keys[ssh_fingerprint] = key
-
- return keys
-
-
-@contextlib.contextmanager
-def _get_ssh_key_file_for_import(original_key_file, service):
- """Return an SSH key file that can be imported into monkeysphere.
-
- If the key file is in PEM format, the key file can be used as it is.
- Otherwise, if the file is in the OpenSSH key format, which is default since
- 7.8, then convert it to PEM format.
-
- """
- if service != 'ssh':
- yield original_key_file
- return
-
- first_line = open(original_key_file, 'r').readline()
- if '--BEGIN OPENSSH PRIVATE KEY--' not in first_line:
- yield original_key_file
- return
-
- with tempfile.TemporaryDirectory() as temp_directory:
- key_file = os.path.join(temp_directory, 'ssh_key_file')
- shutil.copy2(original_key_file, key_file)
- # Convert OpenSSH format to PEM
- subprocess.run(
- ['ssh-keygen', '-p', '-N', '', '-m', 'PEM', '-f', key_file],
- check=True)
- yield key_file
-
-
-def subcommand_host_show_keys(arguments):
- """Show host key fingerprints."""
- print(json.dumps({'keys': get_merged_keys(arguments.key_id)}))
-
-
-def subcommand_host_import_key(arguments, second_run=False):
- """Import host SSH key."""
- keys = get_merged_keys()
- if arguments.ssh_fingerprint not in keys:
- raise Exception('Unknown SSH fingerprint')
-
- key = keys[arguments.ssh_fingerprint]
- if '*' in key['available_domains']:
- key['available_domains'] = arguments.domains
-
- if 'openpgp_fingerprint' not in key and not second_run:
- env = dict(os.environ, MONKEYSPHERE_PROMPT='false')
- with _get_ssh_key_file_for_import(key['key_file'],
- key['service']) as key_file:
- subprocess.check_call([
- 'monkeysphere-host', 'import-key', key_file,
- key['service'] + '://' + key['available_domains'][0]
- ], env=env)
-
- subcommand_host_import_key(arguments, second_run=True)
- else:
- for domain in key['available_domains']:
- if domain in key['imported_domains']:
- continue
-
- env = dict(os.environ, MONKEYSPHERE_PROMPT='false')
- subprocess.check_call([
- 'monkeysphere-host', 'add-servicename',
- key['service'] + '://' + domain, key['openpgp_fingerprint']
- ], env=env)
-
-
-def subcommand_host_publish_key(arguments):
- """Push host key to keyserver."""
- # setting TMPDIR as workaround for Debian bug #656750
- proc = subprocess.Popen(
- ['monkeysphere-host', 'publish-keys'] + arguments.key_ids,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- env=dict(os.environ,
- TMPDIR='/var/lib/monkeysphere/authentication/tmp/',
- MONKEYSPHERE_PROMPT='false'))
- output, error = proc.communicate()
- output, error = output.decode(), error.decode()
- if proc.returncode != 0:
- raise Exception(output, error)
-
- print(output)
-
-
-def subcommand_host_cancel_publish(arguments):
- """Kill a running publish process."""
- process = psutil.Process(int(arguments.pid))
-
- # Perform tight checks on the process before killing for security.
- arguments = process.cmdline()
- if not arguments:
- # Process already completed
- return
-
- # Remove the sudo prefix if present
- while arguments[0] == 'sudo' or arguments[0].startswith('-'):
- arguments = arguments[1:]
-
- if len(arguments) >= 2 and \
- arguments[0].split('/')[-1] == 'monkeysphere' and \
- arguments[1] == 'host-publish-key':
- process.send_signal(signal.SIGTERM)
-
-
-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/debian/freedombox.maintscript b/debian/freedombox.maintscript
index d9b3a7b5e..943a06034 100644
--- a/debian/freedombox.maintscript
+++ b/debian/freedombox.maintscript
@@ -13,3 +13,4 @@ rm_conffile /etc/apt/preferences.d/50freedombox3.pref 20.5~
rm_conffile /etc/plinth/plinth.config 20.12~
rm_conffile /etc/plinth/custom-shortcuts.json 20.12~
rm_conffile /etc/plinth/modules-enabled/coquelicot 20.14~
+rm_conffile /etc/plinth/modules-enabled/monkeysphere 21.16~
diff --git a/plinth/modules/help/tests/test_views.py b/plinth/modules/help/tests/test_views.py
index 3ab4c53ab..331ab07d9 100644
--- a/plinth/modules/help/tests/test_views.py
+++ b/plinth/modules/help/tests/test_views.py
@@ -109,17 +109,16 @@ MANUAL_PAGES = ('Apache_userdir', 'APU', 'Backups', 'BananaPro', 'BeagleBone',
'freedombox-manual', 'GettingHelp', 'GitWeb', 'Hardware',
'I2P', 'Ikiwiki', 'Infinoted', 'Introduction', 'JSXC',
'LetsEncrypt', 'Maker', 'MatrixSynapse', 'MediaWiki',
- 'Minetest', 'MiniDLNA', 'MLDonkey', 'Monkeysphere', 'Mumble',
- 'NameServices', 'Networks', 'OpenVPN', 'OrangePiZero',
- 'PageKite', 'pcDuino3', 'Performance', 'PineA64+',
- 'PioneerEdition', 'Plinth', 'Power', 'Privoxy', 'Quassel',
- 'QuickStart', 'Radicale', 'RaspberryPi2', 'RaspberryPi3B+',
- 'RaspberryPi3B', 'RaspberryPi4B', 'ReleaseNotes', 'Rock64',
- 'RockPro64', 'Roundcube', 'Samba', 'Searx', 'SecureShell',
- 'Security', 'ServiceDiscovery', 'Shadowsocks', 'Sharing',
- 'Snapshots', 'Storage', 'Syncthing', 'TinyTinyRSS', 'Tor',
- 'Transmission', 'Upgrades', 'USBWiFi', 'Users', 'VirtualBox',
- 'WireGuard')
+ 'Minetest', 'MiniDLNA', 'MLDonkey', 'Mumble', 'NameServices',
+ 'Networks', 'OpenVPN', 'OrangePiZero', 'PageKite', 'pcDuino3',
+ 'Performance', 'PineA64+', 'PioneerEdition', 'Plinth', 'Power',
+ 'Privoxy', 'Quassel', 'QuickStart', 'Radicale', 'RaspberryPi2',
+ 'RaspberryPi3B+', 'RaspberryPi3B', 'RaspberryPi4B',
+ 'ReleaseNotes', 'Rock64', 'RockPro64', 'Roundcube', 'Samba',
+ 'Searx', 'SecureShell', 'Security', 'ServiceDiscovery',
+ 'Shadowsocks', 'Sharing', 'Snapshots', 'Storage', 'Syncthing',
+ 'TinyTinyRSS', 'Tor', 'Transmission', 'Upgrades', 'USBWiFi',
+ 'Users', 'VirtualBox', 'WireGuard')
_restricted_reason = ('Needs installed manual. '
'CI speed-optimized workspace does not provide it.')
not_restricted_environment = pytest.mark.skipif(not canary.exists(),
diff --git a/plinth/modules/monkeysphere/__init__.py b/plinth/modules/monkeysphere/__init__.py
deleted file mode 100644
index c6aea2286..000000000
--- a/plinth/modules/monkeysphere/__init__.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-FreedomBox app for monkeysphere.
-"""
-
-from django.utils.translation import gettext_lazy as _
-
-from plinth import app as app_module
-from plinth import menu
-from plinth.modules.backups.components import BackupRestore
-from plinth.modules.users.components import UsersAndGroups
-from plinth.package import Packages
-
-from . import manifest
-
-_description = [
- _('With Monkeysphere, an OpenPGP key can be generated for each configured '
- 'domain serving SSH. The OpenPGP public key can then be uploaded to the '
- 'OpenPGP keyservers. Users connecting to this machine through SSH can '
- 'verify that they are connecting to the correct host. For users to '
- 'trust the key, at least one person (usually the machine owner) must '
- 'sign the key using the regular OpenPGP key signing process. See the '
- ' '
- 'Monkeysphere SSH documentation for more details.'),
- _('Monkeysphere can also generate an OpenPGP key for each Secure Web '
- 'Server (HTTPS) certificate installed on this machine. The OpenPGP '
- 'public key can then be uploaded to the OpenPGP keyservers. Users '
- 'accessing the web server through HTTPS can verify that they are '
- 'connecting to the correct host. To validate the certificate, the user '
- 'will need to install some software that is available on the '
- ' Monkeysphere '
- 'website.')
-]
-
-app = None
-
-
-class MonkeysphereApp(app_module.App):
- """FreedomBox app for Monkeysphere."""
-
- app_id = 'monkeysphere'
-
- _version = 1
-
- def __init__(self):
- """Create components for the app."""
- super().__init__()
-
- info = app_module.Info(app_id=self.app_id, version=self._version,
- name=_('Monkeysphere'), icon='fa-certificate',
- description=_description,
- manual_page='Monkeysphere')
- self.add(info)
-
- menu_item = menu.Menu('menu-monkeysphere', info.name, None, info.icon,
- 'monkeysphere:index', parent_url_name='system',
- advanced=True)
- self.add(menu_item)
-
- packages = Packages('packages-monkeysphere', ['monkeysphere'])
- self.add(packages)
-
- users_and_groups = UsersAndGroups('users-and-groups-monkeysphere',
- reserved_usernames=['monkeysphere'])
- self.add(users_and_groups)
-
- backup_restore = BackupRestore('backup-restore-monkeysphere',
- **manifest.backup)
- self.add(backup_restore)
-
-
-def setup(helper, old_version=None):
- """Install and configure the module."""
- app.setup(old_version)
diff --git a/plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere b/plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere
deleted file mode 100644
index 2de664397..000000000
--- a/plinth/modules/monkeysphere/data/etc/plinth/modules-enabled/monkeysphere
+++ /dev/null
@@ -1 +0,0 @@
-plinth.modules.monkeysphere
diff --git a/plinth/modules/monkeysphere/manifest.py b/plinth/modules/monkeysphere/manifest.py
deleted file mode 100644
index 0f5708de6..000000000
--- a/plinth/modules/monkeysphere/manifest.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Application manfiest for monkeysphere.
-"""
-
-backup = {
- 'config': {
- 'directories': ['/etc/monkeysphere/']
- },
- 'secrets': {
- 'directories': ['/var/lib/monkeysphere/']
- }
-}
diff --git a/plinth/modules/monkeysphere/static/monkeysphere.css b/plinth/modules/monkeysphere/static/monkeysphere.css
deleted file mode 100644
index 323f40788..000000000
--- a/plinth/modules/monkeysphere/static/monkeysphere.css
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-# SPDX-License-Identifier: AGPL-3.0-or-later
-*/
-
-td li {
- list-style: none;
- line-height: 2rem;
-}
-
-td ul {
- padding: 0;
-}
-
-.form-action.pull-right {
- margin-right: 0.625rem;
-}
-
-.form-action button {
- width: 7.875rem;
-}
diff --git a/plinth/modules/monkeysphere/templates/monkeysphere.html b/plinth/modules/monkeysphere/templates/monkeysphere.html
deleted file mode 100644
index f74d2f132..000000000
--- a/plinth/modules/monkeysphere/templates/monkeysphere.html
+++ /dev/null
@@ -1,136 +0,0 @@
-{% extends "app.html" %}
-{% comment %}
-# SPDX-License-Identifier: AGPL-3.0-or-later
-{% endcomment %}
-
-{% load bootstrap %}
-{% load i18n %}
-{% load static %}
-
-{% block page_head %}
-
-{% endblock %}
-
-{% block configuration %}
-
- {% if running %}
-
-
- {% trans "Publishing key to keyserver..." %}
-
-
-
- {% endif %}
-
-
-
-
-
- {% trans "Service" %}
- {% trans "Domains" %}
- {% trans "OpenPGP Fingerprint" %}
-
-
-
-
- {% for key in status.keys.values|dictsort:"ssh_fingerprint" %}
-
-
- {% if key.service == 'ssh' %}
- {% trans "Secure Shell" %}
- {% elif key.service == 'https' %}
- {% trans "Web Server" %}
- {% else %}
- {% trans "Other" %}
- {% endif %}
-
-
-
- {% for domain in key.all_domains %}
- {% if domain not in key.imported_domains %}
- -
-
- {{ domain }}
-
- {% elif domain not in key.available_domains %}
- -
-
- {{ domain }}
-
- {% else %}
- -
-
- {{ domain }}
-
- {% endif %}
- {% endfor %}
-
-
-
- {% if key.openpgp_fingerprint %}
-
- {{ key.openpgp_fingerprint }}
-
- {% else %}
- {% trans "-" %}
- {% endif %}
-
-
- {% if not key.openpgp_fingerprint %}
-
- {% else %}
- {% if not running %}
-
- {% endif %}
- {% if key.importable_domains %}
-
- {% endif %}
- {% endif %}
-
-
- {% endfor %}
-
-
-
-
-{% endblock %}
diff --git a/plinth/modules/monkeysphere/templates/monkeysphere_details.html b/plinth/modules/monkeysphere/templates/monkeysphere_details.html
deleted file mode 100644
index d3a74ffd1..000000000
--- a/plinth/modules/monkeysphere/templates/monkeysphere_details.html
+++ /dev/null
@@ -1,85 +0,0 @@
-{% extends "base.html" %}
-{% comment %}
-# SPDX-License-Identifier: AGPL-3.0-or-later
-{% endcomment %}
-
-{% load bootstrap %}
-{% load i18n %}
-
-{% block content %}
-
- {% trans "Monkeysphere" %}
-
-
-
-
-
- {% trans "OpenPGP Fingerprint" %}
- {{ key.openpgp_fingerprint }}
-
-
- {% trans "OpenPGP User IDs" %}
- {{ key.uids|join:', ' }}
-
-
- {% trans "Key Import Date" %}
- {{ key.date }}
-
-
- {% trans "SSH Key Type" %}
- {{ key.ssh_key_type }}
-
-
- {% trans "SSH Key Size" %}
- {{ key.ssh_key_size }}
-
-
- {% trans "SSH Fingerprint" %}
- {{ key.ssh_fingerprint }}
-
-
- {% trans "Service" %}
-
- {% if key.service == 'ssh' %}
- {% trans "Secure Shell" %}
- {% elif key.service == 'https' %}
- {% trans "Web Server" %}
- {% else %}
- {% trans "Other" %}
- {% endif %}
-
-
-
- {% trans "Key File" %}
- {{ key.key_file }}
-
-
- {% trans "Available Domains" %}
- {{ key.available_domains|join:', ' }}
-
-
- {% trans "Added Domains" %}
- {{ key.imported_domains|join:', ' }}
-
-
-
-
-
-
- {% blocktrans trimmed %}
- After this key is published to the keyservers, it can be signed using
- GnuPG with the following commands:
- {% endblocktrans %}
-
-
-# {% trans "Download the key" %}
-gpg --recv-key {{ key.openpgp_fingerprint }}
-
-# {% trans "Sign the key" %}
-gpg --sign-key {{ key.openpgp_fingerprint }}
-
-# {% trans "Send the key back to the keyservers" %}
-gpg --send-key {{ key.openpgp_fingerprint }}
-
-
-{% endblock %}
diff --git a/plinth/modules/monkeysphere/tests/__init__.py b/plinth/modules/monkeysphere/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/plinth/modules/monkeysphere/tests/test_functional.py b/plinth/modules/monkeysphere/tests/test_functional.py
deleted file mode 100644
index bd59df726..000000000
--- a/plinth/modules/monkeysphere/tests/test_functional.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Functional, browser based tests for monkeysphere app.
-"""
-
-import pytest
-from plinth.tests import functional
-
-pytestmark = [pytest.mark.system, pytest.mark.monkeysphere]
-
-
-@pytest.fixture(scope='module', autouse=True)
-def fixture_background(session_browser):
- """Login and install the app."""
- functional.login(session_browser)
- functional.set_advanced_mode(session_browser, True)
- functional.install(session_browser, 'monkeysphere')
- functional.set_domain_name(session_browser, 'mydomain.example')
- yield
-
-
-def test_import_ssh_keys(session_browser):
- """Test importing SSH keys."""
- _import_key(session_browser, 'ssh', 'mydomain.example')
- _assert_imported_key(session_browser, 'ssh', 'mydomain.example')
-
-
-def test_import_https_keys(session_browser):
- """Test importing HTTPS keys."""
- _import_key(session_browser, 'https', 'mydomain.example')
- _assert_imported_key(session_browser, 'https', 'mydomain.example')
-
-
-def test_publish_ssh_keys(session_browser):
- """Test publishing SSH keys."""
- _import_key(session_browser, 'ssh', 'mydomain.example')
- _publish_key(session_browser, 'ssh', 'mydomain.example')
-
-
-def test_publish_https_keys(session_browser):
- """Test publishing HTTPS keys."""
- _import_key(session_browser, 'https', 'mydomain.example')
- _publish_key(session_browser, 'https', 'mydomain.example')
-
-
-def test_backup_restore(session_browser):
- """Test backup and restore of keys"""
- _import_key(session_browser, 'ssh', 'mydomain.example')
- _import_key(session_browser, 'https', 'mydomain.example')
- functional.backup_create(session_browser, 'monkeysphere',
- 'test_monkeysphere')
-
- functional.backup_restore(session_browser, 'monkeysphere',
- 'test_monkeysphere')
- _assert_imported_key(session_browser, 'ssh', 'mydomain.example')
- _assert_imported_key(session_browser, 'https', 'mydomain.example')
-
-
-def _find_domain(browser, key_type, domain_type, domain):
- """Iterate every domain of a given type which given key type."""
- keys_of_type = browser.find_by_css(
- '.monkeysphere-service-{}'.format(key_type))
- for key_of_type in keys_of_type:
- search_domains = key_of_type.find_by_css(
- '.monkeysphere-{}-domain'.format(domain_type))
- for search_domain in search_domains:
- if search_domain.text == domain:
- return key_of_type, search_domain
-
- raise IndexError('Domain not found')
-
-
-def _import_key(browser, key_type, domain):
- """Import a key of specified type for given domain into monkeysphere."""
- try:
- _assert_imported_key(browser, key_type, domain)
- except IndexError:
- pass
- else:
- return
-
- key, _ = _find_domain(browser, key_type, 'importable', domain)
- with functional.wait_for_page_update(browser):
- key.find_by_css('.button-import').click()
-
-
-def _assert_imported_key(browser, key_type, domain):
- """Assert that a key of specified type for given domain was imported.."""
- functional.nav_to_module(browser, 'monkeysphere')
- return _find_domain(browser, key_type, 'imported', domain)
-
-
-def _publish_key(browser, key_type, domain):
- """Publish a key of specified type for given domain from monkeysphere."""
- functional.nav_to_module(browser, 'monkeysphere')
- key, _ = _find_domain(browser, key_type, 'imported', domain)
- with functional.wait_for_page_update(browser):
- key.find_by_css('.button-publish').click()
-
- functional.wait_for_config_update(browser, 'monkeysphere')
diff --git a/plinth/modules/monkeysphere/urls.py b/plinth/modules/monkeysphere/urls.py
deleted file mode 100644
index 68e1cb215..000000000
--- a/plinth/modules/monkeysphere/urls.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-URLs for the monkeysphere module.
-"""
-
-from django.urls import re_path
-
-from . import views
-
-urlpatterns = [
- re_path(r'^sys/monkeysphere/$', views.index, name='index'),
- re_path(r'^sys/monkeysphere/(?P[0-9A-Za-z:+/]+)/import/$',
- views.import_key, name='import'),
- re_path(r'^sys/monkeysphere/(?P[0-9A-Fa-f]+)/details/$',
- views.details, name='details'),
- re_path(r'^sys/monkeysphere/(?P[0-9A-Fa-f]+)/publish/$',
- views.publish, name='publish'),
- re_path(r'^sys/monkeysphere/cancel/$', views.cancel, name='cancel'),
-]
diff --git a/plinth/modules/monkeysphere/views.py b/plinth/modules/monkeysphere/views.py
deleted file mode 100644
index 27c3c22a9..000000000
--- a/plinth/modules/monkeysphere/views.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Views for the monkeysphere module.
-"""
-
-import json
-
-from django.contrib import messages
-from django.shortcuts import redirect
-from django.template.response import TemplateResponse
-from django.urls import reverse_lazy
-from django.utils.translation import gettext as _
-from django.views.decorators.http import require_POST
-
-from plinth import actions
-from plinth.modules import monkeysphere, names
-
-publish_process = None
-
-
-def index(request):
- """Serve configuration page."""
- _collect_publish_result(request)
- status = get_status()
- return TemplateResponse(
- request, 'monkeysphere.html', {
- 'app_info': monkeysphere.app.info,
- 'title': monkeysphere.app.info.name,
- 'status': status,
- 'running': bool(publish_process),
- 'refresh_page_sec': 3 if bool(publish_process) else None,
- })
-
-
-@require_POST
-def import_key(request, ssh_fingerprint):
- """Import a key into monkeysphere."""
- keys = get_keys()
- available_domains = keys[ssh_fingerprint]['available_domains']
- try:
- actions.superuser_run('monkeysphere',
- ['host-import-key', ssh_fingerprint] +
- list(available_domains))
- messages.success(request, _('Imported key.'))
- except actions.ActionError as exception:
- messages.error(request, str(exception))
-
- return redirect(reverse_lazy('monkeysphere:index'))
-
-
-def details(request, fingerprint):
- """Get details for an OpenPGP key."""
- return TemplateResponse(request, 'monkeysphere_details.html', {
- 'title': monkeysphere.app.info.name,
- 'key': get_key(fingerprint)
- })
-
-
-@require_POST
-def publish(request, fingerprint):
- """Publish OpenPGP key for SSH service."""
- global publish_process
- if not publish_process:
- publish_process = actions.superuser_run(
- 'monkeysphere', ['host-publish-key', fingerprint],
- run_in_background=True)
-
- return redirect(reverse_lazy('monkeysphere:index'))
-
-
-@require_POST
-def cancel(request):
- """Cancel ongoing process."""
- global publish_process
- if publish_process:
- actions.superuser_run(
- 'monkeysphere', ['host-cancel-publish',
- str(publish_process.pid)])
- publish_process = None
- messages.info(request, _('Cancelled key publishing.'))
-
- return redirect(reverse_lazy('monkeysphere:index'))
-
-
-def get_status():
- """Get the current status."""
- return {'keys': get_keys()}
-
-
-def get_keys(fingerprint=None):
- """Get keys."""
- fingerprint = [fingerprint] if fingerprint else []
- output = actions.superuser_run('monkeysphere',
- ['host-show-keys'] + fingerprint)
- keys = json.loads(output)['keys']
-
- domains = names.components.DomainName.list_names()
- for key in keys.values():
- key['imported_domains'] = set(key.get('imported_domains', []))
- key['available_domains'] = set(key.get('available_domains', []))
- if '*' in key['available_domains']:
- key['available_domains'] = set(domains)
-
- key['all_domains'] = sorted(key['available_domains'].union(
- key['imported_domains']))
- key['importable_domains'] = key['available_domains'] \
- .difference(key['imported_domains'])
-
- return keys
-
-
-def get_key(fingerprint):
- """Get key by fingerprint."""
- keys = get_keys(fingerprint)
- return list(keys.values())[0] if len(keys) else None
-
-
-def _collect_publish_result(request):
- """Handle publish process completion."""
- global publish_process
- if not publish_process:
- return
-
- return_code = publish_process.poll()
-
- # Publish process is not complete yet
- if return_code is None:
- return
-
- if not return_code:
- messages.success(request, _('Published key to keyserver.'))
- else:
- messages.error(request, _('Error occurred while publishing key.'))
-
- publish_process = None
diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py
index 10e6511a9..f5738a137 100644
--- a/plinth/tests/functional/__init__.py
+++ b/plinth/tests/functional/__init__.py
@@ -50,9 +50,9 @@ _site_url = {
_sys_modules = [
'avahi', 'backups', 'bind', 'cockpit', 'config', 'datetime', 'diagnostics',
- 'dynamicdns', 'firewall', 'letsencrypt', 'monkeysphere', 'names',
- 'networks', 'pagekite', 'performance', 'power', 'security', 'snapshot',
- 'ssh', 'storage', 'upgrades', 'users'
+ 'dynamicdns', 'firewall', 'letsencrypt', 'names', 'networks', 'pagekite',
+ 'performance', 'power', 'security', 'snapshot', 'ssh', 'storage',
+ 'upgrades', 'users'
]
diff --git a/pyproject.toml b/pyproject.toml
index 2c77234ca..d0d36c748 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -40,7 +40,6 @@ markers = [
"minetest",
"minidlna",
"mldonkey",
- "monkeysphere",
"mumble",
"openvpn",
"pagekite",
diff --git a/setup.py b/setup.py
index 52e46fd7f..2d82edf1d 100755
--- a/setup.py
+++ b/setup.py
@@ -39,6 +39,7 @@ DISABLED_APPS_TO_REMOVE = [
'apps',
'coquelicot',
'diaspora',
+ 'monkeysphere',
'owncloud',
'system',
'xmpp',
From 621cb675272281400db801200f32a9ea61ae5510 Mon Sep 17 00:00:00 2001
From: Joseph Nuthalapati
Date: Mon, 20 Dec 2021 14:17:17 -0800
Subject: [PATCH 27/32] diaspora: Drop app that was never finished.
Signed-off-by: Joseph Nuthalapati
[sunil: Add to configuration file removal in Debian package]
Signed-off-by: Sunil Mohan Adapa
Reviewed-by: Sunil Mohan Adapa
---
actions/diaspora | 146 -------------
debian/copyright | 4 +-
debian/freedombox.maintscript | 1 +
plinth/modules/diaspora/__init__.py | 194 ------------------
plinth/modules/diaspora/forms.py | 13 --
plinth/modules/diaspora/manifest.py | 33 ---
.../templates/diaspora-post-setup.html | 24 ---
.../templates/diaspora-pre-setup.html | 47 -----
plinth/modules/diaspora/tests/__init__.py | 1 -
.../diaspora/tests/test_apache_config.py | 25 ---
plinth/modules/diaspora/urls.py | 14 --
plinth/modules/diaspora/views.py | 80 --------
static/themes/default/icons/diaspora.png | Bin 10630 -> 0 bytes
static/themes/default/icons/diaspora.svg | 62 ------
14 files changed, 2 insertions(+), 642 deletions(-)
delete mode 100755 actions/diaspora
delete mode 100644 plinth/modules/diaspora/__init__.py
delete mode 100644 plinth/modules/diaspora/forms.py
delete mode 100644 plinth/modules/diaspora/manifest.py
delete mode 100644 plinth/modules/diaspora/templates/diaspora-post-setup.html
delete mode 100644 plinth/modules/diaspora/templates/diaspora-pre-setup.html
delete mode 100644 plinth/modules/diaspora/tests/__init__.py
delete mode 100644 plinth/modules/diaspora/tests/test_apache_config.py
delete mode 100644 plinth/modules/diaspora/urls.py
delete mode 100644 plinth/modules/diaspora/views.py
delete mode 100644 static/themes/default/icons/diaspora.png
delete mode 100644 static/themes/default/icons/diaspora.svg
diff --git a/actions/diaspora b/actions/diaspora
deleted file mode 100755
index ef6ffa52d..000000000
--- a/actions/diaspora
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/python3
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Configuration helper for diaspora* pod.
-"""
-
-import argparse
-import subprocess
-
-import augeas
-
-from plinth import action_utils
-from plinth.modules import diaspora
-
-DIASPORA_YAML = "/etc/diaspora/diaspora.yml"
-
-
-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='Preseed debconf values before packages are installed.')
- subparsers.add_parser(
- 'enable-user-registrations',
- help='Allow users to sign up to this diaspora* pod without an '
- 'invitation.')
- subparsers.add_parser(
- 'disable-user-registrations',
- help='Allow only users with an invitation to register to this '
- 'diaspora* pod')
- subparsers.add_parser('start-diaspora', help='Start diaspora* service')
- subparsers.add_parser(
- 'disable-ssl', help="Disable SSL on the diaspora* application server")
- setup = subparsers.add_parser('setup',
- help='Set Domain name for diaspora*')
- setup.add_argument('--domain-name',
- help='The domain name that will be used by diaspora*')
-
- return parser.parse_args()
-
-
-def subcommand_setup(arguments):
- """Set the domain_name in diaspora configuration files"""
- domain_name = arguments.domain_name
- with open('/etc/diaspora/domain_name', 'w') as dnf:
- dnf.write(domain_name)
- set_domain_name(domain_name)
- uncomment_user_registrations()
-
-
-def set_domain_name(domain_name):
- """Write a new domain name to diaspora configuration files"""
- # This did not set the domain_name
- # action_utils.dpkg_reconfigure('diaspora-common',
- # {'url': domain_name})
- # Manually changing the domain name in the conf files.
- conf_file = '/etc/diaspora.conf'
- aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
- augeas.Augeas.NO_MODL_AUTOLOAD)
-
- # lens for shell-script config file
- aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
- aug.set('/augeas/load/Shellvars/incl[last() + 1]', conf_file)
- aug.load()
-
- aug.set('/files/etc/diaspora.conf/SERVERNAME', '"{}"'.format(domain_name))
- aug.set('/files/etc/diaspora.conf/ENVIRONMENT_URL',
- 'http://{}:3000'.format(domain_name))
- aug.save()
-
- diaspora.generate_apache_configuration(
- '/etc/apache2/conf-available/diaspora-plinth.conf', domain_name)
-
- action_utils.service_enable('diaspora')
- action_utils.service_start('diaspora')
-
-
-def subcommand_disable_ssl(_):
- """
- Disable ssl in the diaspora configuration
- as the apache server takes care of ssl
- """
- # Using sed because ruamel.yaml has a bug for this kind of files
- subprocess.call([
- "sed", "-i", "s/#require_ssl: true/require_ssl: false/g", DIASPORA_YAML
- ])
-
-
-def uncomment_user_registrations():
- """Uncomment the enable_registrations line which is commented by default"""
- subprocess.call([
- "sed", "-i", "s/#enable_registrations/enable_registrations/g",
- DIASPORA_YAML
- ])
-
-
-def subcommand_enable_user_registrations(_):
- """Enable new user registrations on the diaspora* pod """
- subprocess.call([
- "sed", "-i",
- "s/enable_registrations: false/enable_registrations: true/g",
- DIASPORA_YAML
- ])
-
-
-def subcommand_disable_user_registrations(_):
- """Disable new user registrations on the diaspora* pod """
- subprocess.call([
- "sed", "-i",
- "s/enable_registrations: true/enable_registrations: false/g",
- DIASPORA_YAML
- ])
-
-
-def subcommand_pre_install(_):
- """Pre installation configuration for diaspora"""
- presets = [
- 'diaspora-common diaspora-common/url string dummy_domain_name',
- 'diaspora-common diaspora-common/dbpass note ',
- 'diaspora-common diaspora-common/enablessl boolean false',
- 'diaspora-common diaspora-common/useletsencrypt string false',
- 'diaspora-common diaspora-common/services multiselect ',
- 'diaspora-common diaspora-common/ssl boolean false',
- 'diaspora-common diaspora-common/pgsql/authmethod-admin string ident',
- 'diaspora-common diaspora-common/letsencrypt boolean false',
- 'diaspora-common diaspora-common/remote/host string localhost',
- 'diaspora-common diaspora-common/database-type string pgsql',
- 'diaspora-common diaspora-common/dbconfig-install boolean true'
- ]
-
- action_utils.debconf_set_selections(presets)
-
-
-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/debian/copyright b/debian/copyright
index 1c2aa540e..bf5b4de20 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -60,9 +60,7 @@ Copyright: 2007 Andrew Wedderburn
Comment: https://commons.wikimedia.org/wiki/File:Deluge-Logo.svg
License: GPL-2+
-Files: static/themes/default/icons/diaspora.png
- static/themes/default/icons/diaspora.svg
- static/themes/default/icons/ejabberd.png
+Files: static/themes/default/icons/ejabberd.png
static/themes/default/icons/ejabberd.svg
static/themes/default/icons/matrixsynapse.svg
static/themes/default/icons/privoxy.png
diff --git a/debian/freedombox.maintscript b/debian/freedombox.maintscript
index 943a06034..290d29cca 100644
--- a/debian/freedombox.maintscript
+++ b/debian/freedombox.maintscript
@@ -13,4 +13,5 @@ rm_conffile /etc/apt/preferences.d/50freedombox3.pref 20.5~
rm_conffile /etc/plinth/plinth.config 20.12~
rm_conffile /etc/plinth/custom-shortcuts.json 20.12~
rm_conffile /etc/plinth/modules-enabled/coquelicot 20.14~
+rm_conffile /etc/plinth/modules-enabled/diaspora 21.16~
rm_conffile /etc/plinth/modules-enabled/monkeysphere 21.16~
diff --git a/plinth/modules/diaspora/__init__.py b/plinth/modules/diaspora/__init__.py
deleted file mode 100644
index 1dbf13aaa..000000000
--- a/plinth/modules/diaspora/__init__.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-import os
-
-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 Daemon
-from plinth.errors import DomainNotRegisteredError
-from plinth.modules.apache.components import Webserver, diagnose_url
-from plinth.modules.firewall.components import Firewall
-from plinth.package import Packages
-from plinth.utils import format_lazy
-
-domain_name_file = "/etc/diaspora/domain_name"
-lazy_domain_name = None # To avoid repeatedly reading from file
-
-
-def is_setup():
- return os.path.exists(domain_name_file)
-
-
-def get_configured_domain_name():
- global lazy_domain_name
- if lazy_domain_name:
- return lazy_domain_name
-
- if not is_setup():
- raise DomainNotRegisteredError()
-
- with open(domain_name_file) as dnf:
- lazy_domain_name = dnf.read().rstrip()
- return lazy_domain_name
-
-
-_description = [
- _('diaspora* is a decentralized social network where you can store '
- 'and control your own data.'),
- format_lazy(
- 'When enabled, the diaspora* pod will be available from '
- 'diaspora.{host} path on the '
- 'web server.'.format(host=get_configured_domain_name()) if is_setup()
- else 'Please register a domain name for your FreedomBox to be able to'
- ' federate with other diaspora* pods.')
-]
-
-app = None
-
-
-class DiasporaApp(app_module.App):
- """FreedomBox app for Diaspora."""
-
- app_id = 'diaspora'
-
- _version = 1
-
- def __init__(self):
- """Create components for the app."""
- super().__init__()
- from . import manifest
-
- info = app_module.Info(app_id=self.app_id, version=self._version,
- name=_('diaspora*'), icon_filename='diaspora',
- short_description=_('Federated Social Network'),
- description=_description,
- clients=manifest.clients)
- self.add(info)
-
- menu_item = menu.Menu('menu-diaspora', info.name,
- info.short_description, info.icon_filename,
- 'diaspora:index', parent_url_name='apps')
- self.add(menu_item)
-
- shortcut = Shortcut('shortcut-diaspora', info.name,
- short_description=info.short_description,
- icon=info.icon_filename, url=None,
- clients=info.clients, login_required=True)
- self.add(shortcut)
-
- packages = Packages('packages-diaspora', ['diaspora'])
- self.add(packages)
-
- firewall = Firewall('firewall-diaspora', info.name,
- ports=['http', 'https'], is_external=True)
- self.add(firewall)
-
- webserver = Webserver('webserver-diaspora', 'diaspora-plinth')
- self.add(webserver)
-
- daemon = Daemon('daemon-diaspora', 'diaspora')
- self.add(daemon)
-
- def diagnose(self):
- """Run diagnostics and return the results."""
- results = super().diagnose()
-
- results.append(
- diagnose_url('http://diaspora.localhost', kind='4',
- check_certificate=False))
- results.append(
- diagnose_url('http://diaspora.localhost', kind='6',
- check_certificate=False))
- results.append(
- diagnose_url(
- 'http://diaspora.{}'.format(get_configured_domain_name()),
- kind='4', check_certificate=False))
-
- return results
-
-
-class Shortcut(frontpage.Shortcut):
- """Frontpage shortcut to use configured domain name for URL."""
-
- def enable(self):
- """Set the proper shortcut URL when enabled."""
- super().enable()
- self.url = 'https://diaspora.{}'.format(get_configured_domain_name())
-
-
-def setup(helper, old_version=None):
- """Install and configure the module."""
- helper.call('pre', actions.superuser_run, 'diaspora', ['pre-install'])
- app.setup(old_version)
- helper.call('custom_config', actions.superuser_run, 'diaspora',
- ['disable-ssl'])
-
-
-def setup_domain_name(domain_name):
- actions.superuser_run('diaspora', ['setup', '--domain-name', domain_name])
- app.enable()
-
-
-def is_user_registrations_enabled():
- """Return whether user registrations are enabled"""
- with open('/etc/diaspora/diaspora.yml') as f:
- for line in f.readlines():
- if "enable_registrations" in line:
- return line.split(":")[1].strip() == "true"
-
-
-def enable_user_registrations():
- """Allow users to register without invitation"""
- actions.superuser_run('diaspora', ['enable-user-registrations'])
-
-
-def disable_user_registrations():
- """Disallow users from registering without invitation"""
- actions.superuser_run('diaspora', ['disable-user-registrations'])
-
-
-def generate_apache_configuration(conf_file, domain_name):
- """Generate Diaspora's apache configuration with the given domain name"""
- open(conf_file, 'w').close()
-
- diaspora_domain_name = ".".join(["diaspora", domain_name])
-
- 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]', conf_file)
- aug.load()
-
- aug.defvar('conf', '/files' + conf_file)
-
- aug.set('$conf/VirtualHost', None)
- aug.defvar('vh', '$conf/VirtualHost')
- aug.set('$vh/arg', diaspora_domain_name)
- aug.set('$vh/directive[1]', 'ServerName')
- aug.set('$vh/directive[1]/arg', diaspora_domain_name)
- aug.set('$vh/directive[2]', 'DocumentRoot')
- aug.set('$vh/directive[2]/arg', '"/var/lib/diaspora/public/"')
-
- aug.set('$vh/Location', None)
- aug.set('$vh/Location/arg', '"/"')
- aug.set('$vh/Location/directive[1]', 'ProxyPass')
- aug.set('$vh/Location/directive[1]/arg',
- '"unix:/var/run/diaspora/diaspora.sock|http://localhost/"')
-
- aug.set('$vh/Location[last() + 1]', None)
- aug.set('$vh/Location[last()]/arg', '"/assets"')
- aug.set('$vh/Location[last()]/directive[1]', 'ProxyPass')
- aug.set('$vh/Location[last()]/directive[1]/arg', '!')
-
- aug.set('$vh/Directory', None)
- aug.set('$vh/Directory/arg', '/var/lib/diaspora/public/')
- aug.set('$vh/Directory/directive[1]', 'Require')
- aug.set('$vh/Directory/directive[1]/arg[1]', 'all')
- aug.set('$vh/Directory/directive[1]/arg[2]', 'granted')
-
- aug.save()
diff --git a/plinth/modules/diaspora/forms.py b/plinth/modules/diaspora/forms.py
deleted file mode 100644
index 89eb3bc7f..000000000
--- a/plinth/modules/diaspora/forms.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Forms for configuring diaspora*
-"""
-
-from django import forms
-from django.utils.translation import gettext_lazy as _
-
-
-class DiasporaAppForm(forms.Form):
- """Service Form with additional fields for diaspora*"""
- is_user_registrations_enabled = forms.BooleanField(
- label=_('Enable new user registrations'), required=False)
diff --git a/plinth/modules/diaspora/manifest.py b/plinth/modules/diaspora/manifest.py
deleted file mode 100644
index 78b988d0a..000000000
--- a/plinth/modules/diaspora/manifest.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-
-from django.utils.translation import gettext_lazy as _
-
-from plinth.clients import store_url
-from plinth.modules import diaspora
-from plinth.utils import format_lazy
-
-clients = [{
- 'name':
- _('dandelion*'),
- 'description':
- _('It is an unofficial webview based client for the '
- 'community-run, distributed social network diaspora*'),
- 'platforms': [{
- 'type': 'store',
- 'os': 'android',
- 'store_name': 'f-droid',
- 'url': store_url('f-droid', 'com.github.dfa.diaspora_android'),
- }]
-}, {
- 'name':
- _('diaspora*'),
- 'platforms': [{
- 'type':
- 'web',
- 'url':
- format_lazy(
- 'https://diaspora.{host}',
- host=diaspora.get_configured_domain_name()
- if diaspora.is_setup() else "")
- }]
-}]
diff --git a/plinth/modules/diaspora/templates/diaspora-post-setup.html b/plinth/modules/diaspora/templates/diaspora-post-setup.html
deleted file mode 100644
index b58f9748d..000000000
--- a/plinth/modules/diaspora/templates/diaspora-post-setup.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{% extends "app.html" %}
-{% comment %}
-# SPDX-License-Identifier: AGPL-3.0-or-later
-{% endcomment %}
-
-{% load i18n %}
-
-{% block description %}
-
-{% for paragraph in description %}
-{{ paragraph|safe }}
-{% endfor %}
-
-
- {% url 'config:index' as index_url %}
- {% blocktrans trimmed with domain_name=domain_name %}
- The diaspora* pod domain is set to {{ domain_name }}. User
- IDs will look like username@diaspora.{{ domain_name }}
- If the FreedomBox domain name is changed, all data of the users
- registered with the previous podname wouldn't be accessible.
- You can access the diaspora* pod at diaspora.{{domain_name}}
- {% endblocktrans %}
-
-{% endblock %}
diff --git a/plinth/modules/diaspora/templates/diaspora-pre-setup.html b/plinth/modules/diaspora/templates/diaspora-pre-setup.html
deleted file mode 100644
index cf0892860..000000000
--- a/plinth/modules/diaspora/templates/diaspora-pre-setup.html
+++ /dev/null
@@ -1,47 +0,0 @@
-{% extends "base.html" %}
-{% comment %}
-# SPDX-License-Identifier: AGPL-3.0-or-later
-{% endcomment %}
-
-{% load bootstrap %}
-{% load i18n %}
-
-{% block content %}
- {% block pagetitle %}
- {{ title }}
- {% endblock %}
-
- {% block description %}
- {% for paragraph in description %}
- {{ paragraph|safe }}
- {% endfor %}
- {% endblock %}
-
-
- {% url 'config:index' as index_url %}
- {% if domain_names|length == 0 %}
- No domain(s) are set. You can setup your domain on the system at
- Configure page.
- {% endif %}
-
-
- {% block status %}
- {% endblock %}
-
- {% block diagnostics %}
- {% endblock %}
-
- {% block configuration %}
- {% if domain_names|length > 0 %}
- {% trans "Configuration" %}
-
- {% endif %}
- {% endblock %}
-{% endblock %}
diff --git a/plinth/modules/diaspora/tests/__init__.py b/plinth/modules/diaspora/tests/__init__.py
deleted file mode 100644
index 1652e34b1..000000000
--- a/plinth/modules/diaspora/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
diff --git a/plinth/modules/diaspora/tests/test_apache_config.py b/plinth/modules/diaspora/tests/test_apache_config.py
deleted file mode 100644
index ce9ee2d5f..000000000
--- a/plinth/modules/diaspora/tests/test_apache_config.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Test Apache configuration generation for diaspora*
-"""
-
-import os
-import tempfile
-
-from plinth.modules import diaspora
-
-
-def test_generate_apache_configuration():
- """Test that Apache configuration is created properly."""
- with tempfile.NamedTemporaryFile() as conf_file:
- diaspora.generate_apache_configuration(conf_file.name,
- 'freedombox.rocks')
-
- assert os.stat(conf_file.name).st_size != 0
-
- with open(conf_file.name) as file_handle:
- contents = file_handle.read()
-
- assert all(
- word in contents
- for word in ['VirtualHost', 'Location', 'Directory', 'assets'])
diff --git a/plinth/modules/diaspora/urls.py b/plinth/modules/diaspora/urls.py
deleted file mode 100644
index cf5dd66a6..000000000
--- a/plinth/modules/diaspora/urls.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-URLs for the diaspora module
-"""
-
-from django.urls import re_path
-
-from .views import DiasporaAppView, DiasporaSetupView
-
-urlpatterns = [
- re_path(r'^apps/diaspora/setup$', DiasporaSetupView.as_view(),
- name='setup'),
- re_path(r'^apps/diaspora/$', DiasporaAppView.as_view(), name='index')
-]
diff --git a/plinth/modules/diaspora/views.py b/plinth/modules/diaspora/views.py
deleted file mode 100644
index 1c449721e..000000000
--- a/plinth/modules/diaspora/views.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Views for the diaspora module
-"""
-
-from django.contrib import messages
-from django.shortcuts import redirect
-from django.urls import reverse_lazy
-from django.utils.translation import gettext as _
-from django.views.generic import FormView
-
-from plinth.forms import DomainSelectionForm
-from plinth.modules import diaspora, names
-from plinth.views import AppView
-
-from .forms import DiasporaAppForm
-
-
-class DiasporaSetupView(FormView):
- """Show diaspora setup page."""
- template_name = 'diaspora-pre-setup.html'
- form_class = DomainSelectionForm
- description = diaspora.app.info.description
- title = diaspora.app.info.name
- success_url = reverse_lazy('diaspora:index')
-
- def form_valid(self, form):
- domain_name = form.cleaned_data['domain_name']
- diaspora.setup_domain_name(domain_name)
-
- return super().form_valid(form)
-
- def get_context_data(self, *args, **kwargs):
- context = super().get_context_data(**kwargs)
- context['description'] = self.description
- context['title'] = self.title
- context['domain_names'] = names.components.DomainName.list_names(
- 'https')
-
- return context
-
-
-class DiasporaAppView(AppView):
- """Show diaspora service page."""
- form_class = DiasporaAppForm
- app_id = 'diaspora'
- template_name = 'diaspora-post-setup.html'
-
- def dispatch(self, request, *args, **kwargs):
- if not diaspora.is_setup():
- return redirect('diaspora:setup')
- return super().dispatch(request, *args, **kwargs)
-
- def get_context_data(self, *args, **kwargs):
- context = super().get_context_data(**kwargs)
- context['domain_name'] = diaspora.get_configured_domain_name()
- return context
-
- def get_initial(self):
- """Return the status of the service to fill in the form."""
- status = super().get_initial()
- status['is_user_registrations_enabled'] = \
- diaspora.is_user_registrations_enabled()
- return status
-
- def form_valid(self, form):
- """Enable/disable user registrations"""
- old_registration = form.initial['is_user_registrations_enabled']
- new_registration = form.cleaned_data['is_user_registrations_enabled']
-
- if old_registration != new_registration:
- if new_registration:
- diaspora.enable_user_registrations()
- messages.success(self.request, _('User registrations enabled'))
- else:
- diaspora.disable_user_registrations()
- messages.success(self.request,
- _('User registrations disabled'))
-
- return super().form_valid(form)
diff --git a/static/themes/default/icons/diaspora.png b/static/themes/default/icons/diaspora.png
deleted file mode 100644
index ab98a53ad8df674dfc828afb1e9f2b9d26e0e9f7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 10630
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
Ak(ZwiHXTl8+xh7qwSX4-c;ID?0`_
z^fZA}llR3LXCQMp?8H&(i!~-ey0uf*0mH9OPxoAzIkxi$w*vzW(_b6CC6L#G4L1A~
zNcD0Ea8UB_@H^Y?x_YaXC9=(jlF2`|Z$xUDIP|;%XN;WxX>h!r$tW3g%FB9a2C(R*
z4~b+Q?E3SZ8rLPIr5)~oWc+K6JX}v#zQpzCipHF{u(rwR=|-D{v#p52{NH0Sb!T#7
zT+9hFxI`pdHf#A<>4(3dvaFqvOk*1##KjHyNT5V~`f900cSm3z@wSqbZB`uJzk(=_
zqFK!=C3F)12%H;r3yW%d>?W-K#>WX4nw^ov(Np@qK>%U*Zen
z2jB&Q(Zvrw%K*Y?(3@%F$E>Etj~z{v{=NY$fM4ttzoU71?*AZ9kP!4xdpfQ{YF
zfDfRY%7y35>sji|{GH162_UH+yG=o<*2TkaZixD>2=^WQ_WYP5OZeXD!iTYmS0CYT1hu^Pf<-j@fUUPJI
z`VZ!E$u2HK0RRj)Wdq#YHw2630AwOSm=`A~)-wPUUX!<2-ye2!mC+OA;`dU1UHQ8t
zti4I8K|B3?)pUNC`aOwHAhZHFjl&8+L?+Zd|KmODH-_xc-R(veMP@m}sC2_i*`4S`(
zbm82-Kim2Sl67Frt$fTLSX)`U+A>jIZf3xx_PRtn?>|*}fe<7rcuXyAVYdxJG?$|G
zHow};4}8Il_MiF*?N{j#QvzvUQX@c;HUm>8ar4S
z$vkw6XUtCgWPv*2lTPkEy*v*HW9cKRraU@X2wVD6*aWE+P~LQhwnsj)SJlt0mO9r2uPlluFRwzU6K0KIE@o`=L8u+4n@^BVt*D
zX=M2QbKWnj!tN|H?N+diY!Jm7E@Br`Ga6f0|=EV=#LndP!aY%icRPuYAfJa#*rg!Dq_}x}S)Y8wJX;r}AAKlc0WjK|7$PV{;2Q*YT&bzbhF2+PV-Cb(m^Vtx6IQzvBpSg+
zv5bGk7RczGn*&CI@5yDtP9zBHgg%>-nLg6azlnEWc8cZ$#6cyOoToe3QG#?4e$o)J
zM1Ip7UqW15@@VKS%>-A-DY#%eVq#)SKk%L7jTv_6m0CSJ#+B@dAwL{f>+)~#|OJ^N@agfe8<5!Xw(!&Kx4;^
zm-PVy*0%&6T9(z!@tJG~g6bDSYIaDe`N?vL^yhF3K#G-$;Pt(5%8p=0tUfGXMob?>
zANGZ?8|@^oVAcjxNgqK9Zp}7_pd?*3Cl}LbRx6
zt${Pffl>!G>T@UhV%vj|&%_vJpc%LT7Nv>i
-
-
-
From b0305746c8a741316515eee63a2100f821dca9f2 Mon Sep 17 00:00:00 2001
From: Joseph Nuthalapati
Date: Mon, 20 Dec 2021 14:17:27 -0800
Subject: [PATCH 28/32] tahoe-lafs: Drop app as it is not being used
Signed-off-by: Joseph Nuthalapati
[sunil: Add to configuration file removal in Debian package and setup.py]
Signed-off-by: Sunil Mohan Adapa
Reviewed-by: Sunil Mohan Adapa
---
actions/tahoe-lafs | 228 ------------------
debian/copyright | 10 -
debian/freedombox.maintscript | 1 +
plinth/modules/tahoe/__init__.py | 194 ---------------
.../apache2/conf-available/tahoe-plinth.conf | 14 --
.../data/etc/plinth/modules-enabled/tahoe | 1 -
.../lib/firewalld/services/tahoe-plinth.xml | 7 -
plinth/modules/tahoe/errors.py | 11 -
plinth/modules/tahoe/manifest.py | 11 -
.../tahoe/templates/tahoe-post-setup.html | 91 -------
.../tahoe/templates/tahoe-pre-setup.html | 47 ----
plinth/modules/tahoe/tests/__init__.py | 0
plinth/modules/tahoe/tests/test_functional.py | 92 -------
plinth/modules/tahoe/urls.py | 18 --
plinth/modules/tahoe/views.py | 64 -----
pyproject.toml | 1 -
setup.py | 1 +
static/themes/default/icons/tahoe-lafs.png | Bin 38261 -> 0 bytes
static/themes/default/icons/tahoe-lafs.svg | 170 -------------
19 files changed, 2 insertions(+), 959 deletions(-)
delete mode 100755 actions/tahoe-lafs
delete mode 100644 plinth/modules/tahoe/__init__.py
delete mode 100644 plinth/modules/tahoe/data/etc/apache2/conf-available/tahoe-plinth.conf
delete mode 100644 plinth/modules/tahoe/data/etc/plinth/modules-enabled/tahoe
delete mode 100644 plinth/modules/tahoe/data/usr/lib/firewalld/services/tahoe-plinth.xml
delete mode 100644 plinth/modules/tahoe/errors.py
delete mode 100644 plinth/modules/tahoe/manifest.py
delete mode 100644 plinth/modules/tahoe/templates/tahoe-post-setup.html
delete mode 100644 plinth/modules/tahoe/templates/tahoe-pre-setup.html
delete mode 100644 plinth/modules/tahoe/tests/__init__.py
delete mode 100644 plinth/modules/tahoe/tests/test_functional.py
delete mode 100644 plinth/modules/tahoe/urls.py
delete mode 100644 plinth/modules/tahoe/views.py
delete mode 100644 static/themes/default/icons/tahoe-lafs.png
delete mode 100644 static/themes/default/icons/tahoe-lafs.svg
diff --git a/actions/tahoe-lafs b/actions/tahoe-lafs
deleted file mode 100755
index 23d6d0b9a..000000000
--- a/actions/tahoe-lafs
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/python3
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Configuration helper for Tahoe-LAFS.
-"""
-
-import argparse
-import grp
-import json
-import os
-import pwd
-import shutil
-import subprocess
-
-import augeas
-import ruamel.yaml
-
-from plinth.modules.tahoe import (introducer_furl_file, introducer_name,
- introducers_file, storage_node_name,
- tahoe_home)
-from plinth.modules.tahoe.errors import TahoeConfigurationError
-from plinth.utils import YAMLFile
-
-domain_name_file = os.path.join(tahoe_home, 'domain_name')
-
-DEFAULT_FILE = '/etc/default/tahoe-lafs'
-
-
-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='Set domain name for Tahoe-LAFS')
- setup.add_argument('--domain-name',
- help='The domain name to be used by Tahoe-LAFS')
- subparsers.add_parser('create-introducer',
- help='Create and start the introducer node')
- subparsers.add_parser('create-storage-node',
- help='Create and start the storage node')
- subparsers.add_parser(
- 'autostart', help='Automatically start all introducers and '
- 'storage nodes on system startup')
- intro_parser_add = subparsers.add_parser(
- 'add-introducer', help="Add an introducer to the storage node's list "
- 'of introducers.')
- intro_parser_add.add_argument(
- '--introducer', help="Add an introducer to the storage node's list "
- 'of introducers Param introducer must be a tuple '
- 'of (pet_name, furl)')
- intro_parser_remove = subparsers.add_parser(
- 'remove-introducer', help='Rename the introducer entry in the '
- 'introducers.yaml file specified by the '
- 'param')
- intro_parser_remove.add_argument(
- '--pet-name', help='The domain name that will be used by '
- 'Tahoe-LAFS')
- subparsers.add_parser(
- 'get-introducers', help='Return a dictionary of all introducers and '
- 'their furls added to the storage node running '
- 'on this FreedomBox.')
- subparsers.add_parser(
- 'get-local-introducer',
- help='Return the name and furl of the introducer '
- 'created on this FreedomBox')
-
- return parser.parse_args()
-
-
-def subcommand_setup(arguments):
- """Actions to be performed after installing Tahoe-LAFS."""
- # Create tahoe group if needed.
- try:
- grp.getgrnam('tahoe-lafs')
- except KeyError:
- subprocess.run(['addgroup', 'tahoe-lafs'], check=True)
-
- # Create tahoe user if needed.
- try:
- pwd.getpwnam('tahoe-lafs')
- except KeyError:
- subprocess.run([
- 'adduser', '--system', '--ingroup', 'tahoe-lafs', '--home',
- '/var/lib/tahoe-lafs', '--gecos',
- 'Tahoe-LAFS distributed file system', 'tahoe-lafs'
- ], check=True)
-
- if not os.path.exists(tahoe_home):
- os.makedirs(tahoe_home, mode=0o755)
-
- shutil.chown(tahoe_home, user='tahoe-lafs', group='tahoe-lafs')
-
- if not os.path.exists(domain_name_file):
- with open(domain_name_file, 'w') as dnf:
- dnf.write(arguments.domain_name)
-
-
-def subcommand_autostart(_):
- """Automatically start all introducers and storage nodes on system startup.
- """
- aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
- augeas.Augeas.NO_MODL_AUTOLOAD)
- aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
- aug.set('/augeas/load/Shellvars/incl[last() + 1]', DEFAULT_FILE)
- aug.load()
-
- aug.set('/files' + DEFAULT_FILE + '/AUTOSTART', 'all')
- aug.save()
-
-
-def get_configured_domain_name():
- """Extract and return the domain name from the domain name file.
-
- Throws TahoeConfigurationError if the domain name file is not found.
- """
- if not os.path.exists(domain_name_file):
- raise TahoeConfigurationError
- else:
- with open(domain_name_file) as dnf:
- return dnf.read().rstrip()
-
-
-def subcommand_create_introducer(_):
- """Create a Tahoe-LAFS introducer on this FreedomBox."""
- os.chdir(tahoe_home)
-
- if not os.path.exists(os.path.join(tahoe_home, introducer_name)):
- subprocess.check_call([
- 'tahoe', 'create-introducer', '--port=3456',
- '--location=tcp:{}:3456'.format(get_configured_domain_name()),
- introducer_name
- ])
-
- subprocess.call(['tahoe', 'start', introducer_name])
-
-
-def subcommand_create_storage_node(_):
- """Create a Tahoe-LAFS storage node on this FreedomBox."""
- os.chdir(tahoe_home)
-
- if not os.path.exists(os.path.join(tahoe_home, storage_node_name)):
- subprocess.check_call([
- 'tahoe', 'create-node', '--nickname=\"storage_node\"',
- '--webport=1234',
- '--hostname={}'.format(get_configured_domain_name()),
- storage_node_name
- ])
- with open(
- os.path.join(tahoe_home, introducer_name, 'private',
- introducer_name + '.furl'), 'r') as furl_file:
- furl = furl_file.read().rstrip()
- conf_dict = {'introducers': {introducer_name: {'furl': furl}}}
- conf_yaml = ruamel.yaml.dump(conf_dict,
- Dumper=ruamel.yaml.RoundTripDumper)
- with open(
- os.path.join(tahoe_home, storage_node_name, 'private',
- 'introducers.yaml'), 'w') as file_handle:
- file_handle.write(conf_yaml)
-
- subprocess.call(['tahoe', 'start', storage_node_name])
-
-
-def subcommand_add_introducer(arguments):
- """Add an introducer to the storage node's list of introducers.
-
- Param introducer must be a tuple of (pet_name, furl).
- """
- with YAMLFile(introducers_file) as conf:
- pet_name, furl = arguments.introducer.split(',')
- conf['introducers'][pet_name] = {'furl': furl}
-
- restart_storage_node()
-
-
-def subcommand_remove_introducer(arguments):
- """Rename the introducer entry in the introducers.yaml file specified
- by the param pet_name
- """
- with YAMLFile(introducers_file) as conf:
- del conf['introducers'][arguments.pet_name]
-
- restart_storage_node()
-
-
-def subcommand_get_introducers(_):
- """Return a dictionary of all introducers and their furls.
-
- The ones added to the storage node running on this FreedomBox.
- """
- with open(introducers_file, 'r') as intro_conf:
- conf = ruamel.yaml.round_trip_load(intro_conf)
-
- introducers = []
- for pet_name in conf['introducers'].keys():
- introducers.append((pet_name, conf['introducers'][pet_name]['furl']))
-
- print(json.dumps(introducers))
-
-
-def subcommand_get_local_introducer(_):
- """Return the name and furl of the introducer created on this FreedomBox
- """
- with open(introducer_furl_file, 'r') as furl_file:
- furl = furl_file.read().rstrip()
-
- print(json.dumps((introducer_name, furl)))
-
-
-def restart_storage_node():
- """Called after exiting context of editing introducers file."""
- try:
- subprocess.run(['tahoe', 'restart', 'storage_node'], check=True)
- except subprocess.CalledProcessError as err:
- print('Failed to restart storage_node with new configuration: %s', err)
-
-
-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/debian/copyright b/debian/copyright
index bf5b4de20..af2e62b80 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -248,16 +248,6 @@ Copyright: Jakob Borg and the Syncthing project
Comment: https://commons.wikimedia.org/wiki/File:SyncthingLogoHorizontal.svg
License: MPL-2.0
-Files: static/themes/default/icons/tahoe-lafs.png
-Copyright: 2017 Kishan Raval
-Comment: https://github.com/thekishanraval/Logos
-License: GPL-3+
-
-Files: static/themes/default/icons/tahoe-lafs.svg
-Copyright: 2006-2018 The Tahoe-LAFS Software Foundation
-Comment: https://github.com/tahoe-lafs/tahoe-lafs/blob/master/misc/build_helpers/icons/logo.svg
-License: GPL-2+
-
Files: static/themes/default/icons/tor.png
static/themes/default/icons/tor.svg
Copyright: The Tor Project, Inc.
diff --git a/debian/freedombox.maintscript b/debian/freedombox.maintscript
index 290d29cca..128d02ff6 100644
--- a/debian/freedombox.maintscript
+++ b/debian/freedombox.maintscript
@@ -15,3 +15,4 @@ rm_conffile /etc/plinth/custom-shortcuts.json 20.12~
rm_conffile /etc/plinth/modules-enabled/coquelicot 20.14~
rm_conffile /etc/plinth/modules-enabled/diaspora 21.16~
rm_conffile /etc/plinth/modules-enabled/monkeysphere 21.16~
+rm_conffile /etc/plinth/modules-enabled/tahoe 21.16~
diff --git a/plinth/modules/tahoe/__init__.py b/plinth/modules/tahoe/__init__.py
deleted file mode 100644
index 6c4bbcd1e..000000000
--- a/plinth/modules/tahoe/__init__.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-FreedomBox app to configure Tahoe-LAFS.
-"""
-
-import json
-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
-from plinth.modules.apache.components import Webserver, diagnose_url
-from plinth.modules.backups.components import BackupRestore
-from plinth.modules.firewall.components import Firewall
-from plinth.package import Packages
-from plinth.utils import format_lazy
-
-from . import manifest
-from .errors import TahoeConfigurationError
-
-_description = [
- _('Tahoe-LAFS is a decentralized secure file storage system. '
- 'It uses provider independent security to store files over a '
- 'distributed network of storage nodes. Even if some of the nodes fail, '
- 'your files can be retrieved from the remaining nodes.'),
- format_lazy(
- _('This {box_name} hosts a storage node and an introducer by default. '
- 'Additional introducers can be added, which will introduce this '
- 'node to the other storage nodes.'), box_name=_(cfg.box_name)),
-]
-
-tahoe_home = '/var/lib/tahoe-lafs'
-introducer_name = 'introducer'
-storage_node_name = 'storage_node'
-domain_name_file = os.path.join(tahoe_home, 'domain_name')
-introducers_file = os.path.join(
- tahoe_home, '{}/private/introducers.yaml'.format(storage_node_name))
-introducer_furl_file = os.path.join(
- tahoe_home, '{0}/private/{0}.furl'.format(introducer_name))
-
-app = None
-
-
-class TahoeApp(app_module.App):
- """FreedomBox app for Tahoe LAFS."""
-
- app_id = 'tahoe'
-
- _version = 1
-
- def __init__(self):
- """Create components for the app."""
- super().__init__()
-
- info = app_module.Info(app_id=self.app_id, version=self._version,
- name=_('Tahoe-LAFS'),
- icon_filename='tahoe-lafs',
- short_description=_('Distributed File Storage'),
- description=_description)
-
- self.add(info)
-
- menu_item = menu.Menu('menu-tahoe', info.name, info.short_description,
- info.icon_filename, 'tahoe:index',
- parent_url_name='apps', advanced=True)
- self.add(menu_item)
-
- shortcut = frontpage.Shortcut(
- 'shortcut-tahoe', info.name,
- short_description=info.short_description, icon=info.icon_filename,
- description=info.description, url=None,
- configure_url=reverse_lazy('tahoe:index'), login_required=True)
- self.add(shortcut)
-
- packages = Packages('packages-tahoe', ['tahoe-lafs'])
- self.add(packages)
-
- firewall = Firewall('firewall-tahoe', info.name,
- ports=['tahoe-plinth'], is_external=True)
- self.add(firewall)
-
- webserver = Webserver('webserver-tahoe', 'tahoe-plinth')
- self.add(webserver)
-
- daemon = Daemon('daemon-tahoe', 'tahoe-lafs')
- self.add(daemon)
-
- backup_restore = BackupRestore('backup-restore-tahoe',
- **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
- domain name is setup.
- """
- return super().is_enabled() and is_setup()
-
- def diagnose(self):
- """Run diagnostics and return the results."""
- results = super().diagnose()
- results.extend([
- diagnose_url('http://localhost:5678', kind='4',
- check_certificate=False),
- diagnose_url('http://localhost:5678', kind='6',
- check_certificate=False),
- diagnose_url('http://{}:5678'.format(get_configured_domain_name()),
- kind='4', check_certificate=False)
- ])
- return results
-
-
-class Shortcut(frontpage.Shortcut):
- """Frontpage shortcut to use configured domain name for URL."""
-
- def enable(self):
- """Set the proper shortcut URL when enabled."""
- super().enable()
- self.url = 'https://{}:5678'.format(get_configured_domain_name())
-
-
-def is_setup():
- """Check whether Tahoe-LAFS is setup"""
- return os.path.exists(domain_name_file)
-
-
-def get_configured_domain_name():
- """Extract and return the domain name from the domain name file.
- Throws TahoeConfigurationError if the domain name file is not found.
- """
- if not os.path.exists(domain_name_file):
- raise TahoeConfigurationError
- else:
- with open(domain_name_file) as dnf:
- return dnf.read().rstrip()
-
-
-def setup(helper, old_version=None):
- """Install and configure the module."""
- app.setup(old_version)
-
-
-def post_setup(configured_domain_name):
- """Actions to be performed after installing tahoe-lafs package."""
- actions.superuser_run('tahoe-lafs',
- ['setup', '--domain-name', configured_domain_name])
- actions.run_as_user('tahoe-lafs', ['create-introducer'],
- become_user='tahoe-lafs')
- actions.run_as_user('tahoe-lafs', ['create-storage-node'],
- become_user='tahoe-lafs')
- actions.superuser_run('tahoe-lafs', ['autostart'])
- app.enable()
-
-
-def add_introducer(introducer):
- """Add an introducer to the storage node's list of introducers.
- Param introducer must be a tuple of (pet_name, furl)
- """
- actions.run_as_user(
- 'tahoe-lafs', ['add-introducer', "--introducer", ",".join(introducer)],
- become_user='tahoe-lafs')
-
-
-def remove_introducer(pet_name):
- """Rename the introducer entry in the introducers.yaml file specified by
- the param pet_name.
- """
- actions.run_as_user('tahoe-lafs',
- ['remove-introducer', '--pet-name', pet_name],
- become_user='tahoe-lafs')
-
-
-def get_introducers():
- """Return a dictionary of all introducers and their furls added to the
- storage node running on this FreedomBox.
- """
- introducers = actions.run_as_user('tahoe-lafs', ['get-introducers'],
- become_user='tahoe-lafs')
-
- return json.loads(introducers)
-
-
-def get_local_introducer():
- """Return the name and furl of the introducer created on this FreedomBox.
- """
- introducer = actions.run_as_user('tahoe-lafs', ['get-local-introducer'],
- become_user='tahoe-lafs')
-
- return json.loads(introducer)
diff --git a/plinth/modules/tahoe/data/etc/apache2/conf-available/tahoe-plinth.conf b/plinth/modules/tahoe/data/etc/apache2/conf-available/tahoe-plinth.conf
deleted file mode 100644
index 80e5c5fdd..000000000
--- a/plinth/modules/tahoe/data/etc/apache2/conf-available/tahoe-plinth.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-# Tahoe-LAFS Storage Node web interface
-
-Listen 5678
-
-# XXX: SSL is not configured?
-# TODO: Use subdomain?
-
-
- Include includes/freedombox-auth-ldap.conf
- Require ldap-group cn=admin,ou=groups,dc=thisbox
-
- ProxyPass http://localhost:1234/
-
-
diff --git a/plinth/modules/tahoe/data/etc/plinth/modules-enabled/tahoe b/plinth/modules/tahoe/data/etc/plinth/modules-enabled/tahoe
deleted file mode 100644
index 2379a52f4..000000000
--- a/plinth/modules/tahoe/data/etc/plinth/modules-enabled/tahoe
+++ /dev/null
@@ -1 +0,0 @@
-#plinth.modules.tahoe
diff --git a/plinth/modules/tahoe/data/usr/lib/firewalld/services/tahoe-plinth.xml b/plinth/modules/tahoe/data/usr/lib/firewalld/services/tahoe-plinth.xml
deleted file mode 100644
index e745d9636..000000000
--- a/plinth/modules/tahoe/data/usr/lib/firewalld/services/tahoe-plinth.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- Tahoe-LAFS
- Tahoe-LAFS is a distributed file storage system
-
-
-
diff --git a/plinth/modules/tahoe/errors.py b/plinth/modules/tahoe/errors.py
deleted file mode 100644
index e767d9221..000000000
--- a/plinth/modules/tahoe/errors.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Errors for Tahoe-LAFS module
-"""
-
-from plinth.errors import PlinthError
-
-
-class TahoeConfigurationError(PlinthError):
- """Tahoe-LAFS has not been configured for domain name."""
- pass
diff --git a/plinth/modules/tahoe/manifest.py b/plinth/modules/tahoe/manifest.py
deleted file mode 100644
index 22fb0dbeb..000000000
--- a/plinth/modules/tahoe/manifest.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Application manfiest for tahoe-lafs.
-"""
-
-backup = {
- 'secrets': {
- 'directories': ['/var/lib/tahoe-lafs/']
- },
- 'services': ['tahoe-lafs']
-}
diff --git a/plinth/modules/tahoe/templates/tahoe-post-setup.html b/plinth/modules/tahoe/templates/tahoe-post-setup.html
deleted file mode 100644
index e59011e5d..000000000
--- a/plinth/modules/tahoe/templates/tahoe-post-setup.html
+++ /dev/null
@@ -1,91 +0,0 @@
-{% extends "app.html" %}
-{% comment %}
-# SPDX-License-Identifier: AGPL-3.0-or-later
-{% endcomment %}
-
-{% load i18n %}
-{% load bootstrap %}
-
-{% block description %}
-
-{% for paragraph in description %}
-{{ paragraph|safe }}
-{% endfor %}
-
-
- {% url 'config:index' as index_url %}
- {% blocktrans trimmed with domain_name=domain_name %}
- The Tahoe-LAFS server domain is set to {{ domain_name }}.
- Changing the FreedomBox domain name needs a reinstall of
- Tahoe-LAFS and you WILL LOSE DATA. You can access Tahoe-LAFS at
- https://{{domain_name}}:5678.
- {% endblocktrans %}
-
-{% endblock %}
-
-{% block configuration %}
- {{ block.super }}
-
- {% trans "Local introducer" %}
-
-
-
-
- {% trans "Pet Name" %}
- furl
-
-
-
- {{ local_introducer.0 }}
- {{ local_introducer.1 }}
-
-
-
-
-
-
-
-
- {% trans "Connected introducers" %}
-
-
-
-
- {% trans "Pet Name" %}
- furl
-
-
- {% for introducer, furl in introducers %}
-
- {{ introducer }}
- {{ furl }}
-
-
-
-
- {% endfor %}
-
-
-
-{% endblock %}
diff --git a/plinth/modules/tahoe/templates/tahoe-pre-setup.html b/plinth/modules/tahoe/templates/tahoe-pre-setup.html
deleted file mode 100644
index 3249ab6a3..000000000
--- a/plinth/modules/tahoe/templates/tahoe-pre-setup.html
+++ /dev/null
@@ -1,47 +0,0 @@
-{% extends "base.html" %}
-{% comment %}
-# SPDX-License-Identifier: AGPL-3.0-or-later
-{% endcomment %}
-
-{% load bootstrap %}
-{% load i18n %}
-
-{% block content %}
- {% block pagetitle %}
- {{ title }}
- {% endblock %}
-
- {% block description %}
- {% for paragraph in description %}
- {{ paragraph|safe }}
- {% endfor %}
- {% endblock %}
-
-
- {% url 'config:index' as index_url %}
- {% if domain_names|length == 0 %}
- No domain(s) are set. You can setup your domain on the system at
- {% trans "Configure" %} page.
- {% endif %}
-
-
- {% block status %}
- {% endblock %}
-
- {% block diagnostics %}
- {% endblock %}
-
- {% block configuration %}
- {% if domain_names|length > 0 %}
- {% trans Configuration %}
-
- {% endif %}
- {% endblock %}
-{% endblock %}
diff --git a/plinth/modules/tahoe/tests/__init__.py b/plinth/modules/tahoe/tests/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/plinth/modules/tahoe/tests/test_functional.py b/plinth/modules/tahoe/tests/test_functional.py
deleted file mode 100644
index 3adf10e85..000000000
--- a/plinth/modules/tahoe/tests/test_functional.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Functional, browser based tests for tahoe app.
-"""
-
-import pytest
-from plinth.tests import functional
-
-pytestmark = [pytest.mark.apps, pytest.mark.tahoe, pytest.mark.skip]
-
-# TODO: When tahoe-lafs is restarted, it leaves a .gnupg folder in
-# /var/lib/tahoe-lafs and failes to start in the next run. Enable tests after
-# this is fixed.
-
-
-class TestTahoeApp(functional.BaseAppTests):
- app_name = 'tahoe'
- has_service = True
- has_web = True
-
- @pytest.fixture(scope='class', autouse=True)
- def fixture_setup(self, session_browser):
- """Setup the app."""
- functional.login(session_browser)
- functional.set_advanced_mode(session_browser, True)
- functional.set_domain_name(session_browser, 'mydomain.example')
- functional.install(session_browser, self.app_name)
- functional.app_select_domain_name(session_browser, self.app_name,
- 'mydomain.example')
-
- def test_default_introducers(self, session_browser):
- """Test default introducers."""
- assert _get_introducer(session_browser, 'mydomain.example', 'local')
- assert _get_introducer(session_browser, 'mydomain.example',
- 'connected')
-
- def test_add_remove_introducers(self, session_browser):
- """Test add and remove introducers."""
- if _get_introducer(session_browser, 'anotherdomain.example',
- 'connected'):
- _remove_introducer(session_browser, 'anotherdomain.example')
-
- _add_introducer(session_browser, 'anotherdomain.example')
- assert _get_introducer(session_browser, 'anotherdomain.example',
- 'connected')
-
- _remove_introducer(session_browser, 'anotherdomain.example')
- assert not _get_introducer(session_browser, 'anotherdomain.example',
- 'connected')
-
- @pytest.mark.backups
- def test_backup_restore(self, session_browser):
- """Test backup and restore of app data."""
- if not _get_introducer(session_browser, 'backupdomain.example',
- 'connected'):
- _add_introducer(session_browser, 'backupdomain.example')
- functional.backup_create(session_browser, self.app_name, 'test_tahoe')
-
- _remove_introducer(session_browser, 'backupdomain.example')
- functional.backup_restore(session_browser, self.app_name, 'test_tahoe')
-
- assert functional.service_is_running(session_browser, self.app_name)
- assert _get_introducer(session_browser, 'backupdomain.example',
- 'connected')
-
-
-def _get_introducer(browser, domain, introducer_type):
- """Return an introducer element with a given type from tahoe-lafs."""
- functional.nav_to_module(browser, 'tahoe')
- css_class = '.{}-introducers .introducer-furl'.format(introducer_type)
- for furl in browser.find_by_css(css_class):
- if domain in furl.text:
- return furl.parent
-
- return None
-
-
-def _add_introducer(browser, domain):
- """Add a new introducer into tahoe-lafs."""
- functional.nav_to_module(browser, 'tahoe')
-
- furl = 'pb://ewe4zdz6kxn7xhuvc7izj2da2gpbgeir@tcp:{}:3456/' \
- 'fko4ivfwgqvybppwar3uehkx6spaaou7'.format(domain)
- browser.fill('pet_name', 'testintroducer')
- browser.fill('furl', furl)
- functional.submit(browser, form_class='form-add-introducer')
-
-
-def _remove_introducer(browser, domain):
- """Remove an introducer from tahoe-lafs."""
- introducer = _get_introducer(browser, domain, 'connected')
- functional.submit(browser, element=introducer.find_by_css('.form-remove'))
diff --git a/plinth/modules/tahoe/urls.py b/plinth/modules/tahoe/urls.py
deleted file mode 100644
index e076a5a95..000000000
--- a/plinth/modules/tahoe/urls.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-URLs for the Tahoe-LAFS module.
-"""
-
-from django.urls import re_path
-
-from . import views
-from .views import TahoeAppView, TahoeSetupView
-
-urlpatterns = [
- re_path(r'^apps/tahoe/setup/$', TahoeSetupView.as_view(), name='setup'),
- re_path(r'^apps/tahoe/add_introducer/$', views.add_introducer,
- name='add-introducer'),
- re_path(r'^apps/tahoe/remove_introducer/(?P[0-9a-zA-Z_]+)/$',
- views.remove_introducer, name='remove-introducer'),
- re_path(r'^apps/tahoe/$', TahoeAppView.as_view(), name='index')
-]
diff --git a/plinth/modules/tahoe/views.py b/plinth/modules/tahoe/views.py
deleted file mode 100644
index 82bfd6510..000000000
--- a/plinth/modules/tahoe/views.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# SPDX-License-Identifier: AGPL-3.0-or-later
-"""
-Views for the Tahoe-LAFS module
-"""
-from django.shortcuts import redirect
-from django.urls import reverse_lazy
-from django.views.generic import FormView
-
-from plinth.forms import DomainSelectionForm
-from plinth.modules import names, tahoe
-from plinth.views import AppView
-
-
-class TahoeSetupView(FormView):
- """Show tahoe-lafs setup page."""
- template_name = 'tahoe-pre-setup.html'
- form_class = DomainSelectionForm
- success_url = reverse_lazy('tahoe:index')
-
- def form_valid(self, form):
- domain_name = form.cleaned_data['domain_name']
- tahoe.post_setup(domain_name)
- return super().form_valid(form)
-
- def get_context_data(self, *args, **kwargs):
- context = super().get_context_data(**kwargs)
- context['description'] = tahoe.app.info.description
- context['title'] = tahoe.app.info.name
- context['domain_names'] = names.components.DomainName.list_names(
- 'tahoe-plinth')
-
- return context
-
-
-class TahoeAppView(AppView):
- """Show tahoe-lafs service page."""
- app_id = 'tahoe'
- template_name = 'tahoe-post-setup.html'
-
- def dispatch(self, request, *args, **kwargs):
- if not tahoe.is_setup():
- return redirect('tahoe:setup')
-
- return super().dispatch(request, *args, **kwargs)
-
- def get_context_data(self, *args, **kwargs):
- context = super().get_context_data(**kwargs)
- context['domain_name'] = tahoe.get_configured_domain_name()
- context['introducers'] = tahoe.get_introducers()
- context['local_introducer'] = tahoe.get_local_introducer()
-
- return context
-
-
-def add_introducer(request):
- if request.method == 'POST':
- tahoe.add_introducer((request.POST['pet_name'], request.POST['furl']))
- return redirect('tahoe:index')
-
-
-def remove_introducer(request, introducer):
- if request.method == 'POST':
- tahoe.remove_introducer(introducer)
- return redirect('tahoe:index')
diff --git a/pyproject.toml b/pyproject.toml
index d0d36c748..0ad41f90b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -59,7 +59,6 @@ markers = [
"storage",
"syncthing",
"system",
- "tahoe",
"tor",
"transmission",
"ttrss",
diff --git a/setup.py b/setup.py
index 2d82edf1d..9855f177a 100755
--- a/setup.py
+++ b/setup.py
@@ -47,6 +47,7 @@ DISABLED_APPS_TO_REMOVE = [
'udiskie',
'restore',
'repro',
+ 'tahoe',
]
REMOVED_FILES = [
diff --git a/static/themes/default/icons/tahoe-lafs.png b/static/themes/default/icons/tahoe-lafs.png
deleted file mode 100644
index bdac72e3ab9ed7751cb2b0400ac9be3846b06f30..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 38261
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