From 126889817645a1e5a25a5a564ac71e884e395f4a Mon Sep 17 00:00:00 2001 From: Veiko Aasa Date: Tue, 27 Feb 2024 09:15:54 +0200 Subject: [PATCH 01/63] gitweb: Fix modifying git repositories when gitweb app is disabled Fixes #2408. - When app is disabled, continue to update the app shortcut's login required property. Otherwise, the value is current after the app is re-enabled. - When public access is enabled, the gitweb-freedombox-auth.conf configuration must be disabled. This can be done even if the configuration is already disabled or does not exist. So, continue doing this. Signed-off-by: Veiko Aasa [sunil: Perform enable public access even if app is disabled] [sunil: Perform shortcut update in all cases even if app is disabled] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/gitweb/__init__.py | 4 +- .../modules/gitweb/tests/test_functional.py | 41 ++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/plinth/modules/gitweb/__init__.py b/plinth/modules/gitweb/__init__.py index 26c9c968b..3d8599217 100644 --- a/plinth/modules/gitweb/__init__.py +++ b/plinth/modules/gitweb/__init__.py @@ -98,7 +98,7 @@ class GitwebApp(app_module.App): def post_init(self): """Perform post initialization operations.""" - if not self.needs_setup() and self.is_enabled(): + if not self.needs_setup(): self.update_service_access() def set_shortcut_login_required(self, login_required): @@ -122,7 +122,7 @@ class GitwebApp(app_module.App): def _disable_public_access(self): """Allow Gitweb app to be accessed by logged-in users only.""" - if not self.auth_webserver.is_conf_enabled(): + if self.is_enabled() and not self.auth_webserver.is_conf_enabled(): self.auth_webserver.enable() self.set_shortcut_login_required(True) diff --git a/plinth/modules/gitweb/tests/test_functional.py b/plinth/modules/gitweb/tests/test_functional.py index 5c833aaff..5f8a67ee7 100644 --- a/plinth/modules/gitweb/tests/test_functional.py +++ b/plinth/modules/gitweb/tests/test_functional.py @@ -63,23 +63,30 @@ class TestGitwebApp(functional.BaseAppTests): @pytest.mark.parametrize('access', ['public', 'private']) @pytest.mark.parametrize('repo_name', ['Test-repo', 'Test-repo.git']) - def test_create_delete_repo(self, session_browser, access, repo_name): + @pytest.mark.parametrize('app_status', ['enabled', 'disabled']) + def test_create_delete_repo(self, session_browser, access, repo_name, + app_status): """Test creating and deleting a repo and accessing with a git client.""" + if app_status == "disabled": + functional.app_disable(session_browser, 'gitweb') + _delete_repo(session_browser, repo_name, ignore_missing=True) _create_repo(session_browser, repo_name, access) assert _repo_exists(session_browser, repo_name, access) - assert _site_repo_exists(session_browser, repo_name) - if access == "public": - assert _repo_is_readable(repo_name) - else: - assert not _repo_is_readable(repo_name) + if app_status == "enabled": + assert _site_repo_exists(session_browser, repo_name) - assert not _repo_is_writable(repo_name) - assert _repo_is_readable(repo_name, with_auth=True) - assert _repo_is_writable(repo_name, with_auth=True) + if access == "public": + assert _repo_is_readable(repo_name) + else: + assert not _repo_is_readable(repo_name) + + assert not _repo_is_writable(repo_name) + assert _repo_is_readable(repo_name, with_auth=True) + assert _repo_is_writable(repo_name, with_auth=True) _delete_repo(session_browser, repo_name) assert not _repo_exists(session_browser, repo_name) @@ -93,8 +100,12 @@ class TestGitwebApp(functional.BaseAppTests): assert _site_repo_exists(session_browser, 'Test-repo') assert not _site_repo_exists(session_browser, 'Test-repo-private') - def test_edit_repo_metadata(self, session_browser): + @pytest.mark.parametrize('app_status', ['enabled', 'disabled']) + def test_edit_repo_metadata(self, session_browser, app_status): """Test edit repo metadata.""" + if app_status == "disabled": + functional.app_disable(session_browser, 'gitweb') + _create_repo(session_browser, 'Test-repo2', 'public', ok_if_exists=True) _delete_repo(session_browser, 'Test-repo', ignore_missing=True) @@ -108,10 +119,12 @@ class TestGitwebApp(functional.BaseAppTests): assert _get_repo_metadata(session_browser, "Test-repo") == repo_metadata - _create_branch('Test-repo', 'branch1') - _set_default_branch(session_browser, 'Test-repo', 'branch1') - assert _get_gitweb_site_default_repo_branch(session_browser, - 'Test-repo') == 'branch1' + if app_status == "enabled": + _create_branch('Test-repo', 'branch1') + _set_default_branch(session_browser, 'Test-repo', 'branch1') + + assert _get_gitweb_site_default_repo_branch( + session_browser, 'Test-repo') == 'branch1' def _create_local_repo(path): From 903059501f4f63a50d26ec8465d91096046a4ee7 Mon Sep 17 00:00:00 2001 From: ikmaak Date: Tue, 27 Feb 2024 09:13:24 +0000 Subject: [PATCH 02/63] Translated using Weblate (Dutch) Currently translated at 99.5% (1550 of 1557 strings) --- plinth/locale/nl/LC_MESSAGES/django.po | 37 ++++++++++---------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/plinth/locale/nl/LC_MESSAGES/django.po b/plinth/locale/nl/LC_MESSAGES/django.po index 797471529..c93251fd5 100644 --- a/plinth/locale/nl/LC_MESSAGES/django.po +++ b/plinth/locale/nl/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-02-12 20:35-0500\n" -"PO-Revision-Date: 2023-12-03 21:05+0000\n" +"PO-Revision-Date: 2024-02-28 10:02+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Dutch \n" @@ -17,7 +17,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.3-dev\n" +"X-Generator: Weblate 5.5-dev\n" "X-Language: nl_NL\n" "X-Source-Language: C\n" @@ -1538,7 +1538,7 @@ msgstr "Voer diagnose uit" #: modules/diagnostics/__init__.py:307 #, no-python-format, python-brace-format msgid "Found {issue_count} issues during routine tests." -msgstr "" +msgstr "{issue_count} problemen gevonden tijdens routinetests." #: modules/diagnostics/__init__.py:308 msgid "Diagnostics results" @@ -1549,30 +1549,22 @@ msgid "Go to diagnostics results" msgstr "Ga naar resultaten van diagnose" #: modules/diagnostics/forms.py:11 -#, fuzzy -#| msgid "Enable Subdomains" msgid "Enable daily run" -msgstr "Subdomeinen Inschakelen" +msgstr "Dagelijkse tests inschakelen" #: modules/diagnostics/forms.py:12 -#, fuzzy -#| msgid "When enabled, FreedomBox automatically updates once a day." msgid "When enabled, diagnostic checks will run once a day." msgstr "" -"Als deze functie is ingeschakeld, wordt FreedomBox automatisch één keer per " -"dag bijgewerkt." +"Als deze functie is ingeschakeld, worden dagelijks diagnostische tests " +"uitgevoerd." #: modules/diagnostics/templates/diagnostics.html:11 -#, fuzzy -#| msgid "Diagnostics" msgid "Diagnostics Run" -msgstr "Diagnose" +msgstr "Diagnose uitvoeren" #: modules/diagnostics/templates/diagnostics.html:17 -#, fuzzy -#| msgid "Run Diagnostics" msgid "Run Diagnostics Now" -msgstr "Voer Diagnostische test uit" +msgstr "Voer Diagnosetests nu uit" #: modules/diagnostics/templates/diagnostics.html:22 msgid "View Results" @@ -3214,7 +3206,7 @@ msgstr "" #: modules/kiwix/templates/kiwix-add-package.html:24 #, python-format msgid "You have %(max_filesize)s of free disk space available." -msgstr "" +msgstr "Er is %(max_filesize)s vrije diskruimte beschikbaar." #: modules/kiwix/templates/kiwix-add-package.html:36 msgid "Upload ZIM file" @@ -3230,6 +3222,8 @@ msgid "" "Delete this package permanently? You may add it back later if you have a " "copy of the ZIM file." msgstr "" +"Dit pakket permanent verwijderen? Het is later terug te zetten met behulp " +"van het ZIM bestand." #: modules/kiwix/templates/kiwix.html:11 msgid "Manage Content Packages" @@ -6946,10 +6940,8 @@ msgid "" msgstr "" #: modules/storage/__init__.py:381 -#, fuzzy -#| msgid "Filesystem" msgid "Read-only root filesystem" -msgstr "Bestandssysteem" +msgstr "Alleen-lezen bestandssysteem" #: modules/storage/__init__.py:391 #, fuzzy @@ -8497,10 +8489,9 @@ msgid "Finished: {name}" msgstr "Klaar: {name}" #: package.py:214 -#, fuzzy, python-brace-format -#| msgid "Package {expression} is not available for install" +#, python-brace-format msgid "Package {package_expression} is not available for install" -msgstr "Pakket {expression} is niet beschikbaar voor installatie" +msgstr "Pakket {package_expression} is niet beschikbaar voor installatie" #: package.py:231 #, python-brace-format From dfaeadee6bdbb8b5129f9c3c6612567563c8eef2 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Mon, 4 Mar 2024 21:00:18 -0500 Subject: [PATCH 03/63] diagnostics: Add tests for get_results Signed-off-by: James Valleroy Reviewed-by: Sunil Mohan Adapa --- .../diagnostics/tests/test_diagnostics.py | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 plinth/modules/diagnostics/tests/test_diagnostics.py diff --git a/plinth/modules/diagnostics/tests/test_diagnostics.py b/plinth/modules/diagnostics/tests/test_diagnostics.py new file mode 100644 index 000000000..f056167aa --- /dev/null +++ b/plinth/modules/diagnostics/tests/test_diagnostics.py @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Tests for Diagnostics app functions.""" + +from collections import OrderedDict +from unittest.mock import patch + +from plinth.app import App, Info +from plinth.modules.diagnostics import get_results + + +class AppTest(App): + """Sample App for testing.""" + app_id = 'test-app' + + def __init__(self): + super().__init__() + info = Info('test-app', 1) + self.add(info) + + +def test_get_results(): + """Test getting the diagnostics results.""" + var = 'plinth.modules.diagnostics.current_results' + with patch(var, {}): + assert get_results() == {'progress_percentage': 100, 'results': {}} + + with patch(var, { + 'apps': [], + 'results': OrderedDict(), + 'progress_percentage': 0 + }): + assert get_results() == { + 'apps': [], + 'results': {}, + 'progress_percentage': 0 + } + + _ = AppTest() + results = OrderedDict({ + 'test-app': { + 'id': 'test-app', + 'diagnosis': [], + 'exception': None, + 'show_rerun_setup': False + } + }) + with patch( + var, { + 'apps': [('test-app', AppTest)], + 'results': results, + 'progress_percentage': 0 + }): + results['test-app'].update({'name': 'test-app'}) + assert get_results() == { + 'apps': [('test-app', AppTest)], + 'results': results, + 'progress_percentage': 0 + } From d512e4268c94e5f76f232ec1cb15b74436e5354e Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Tue, 5 Mar 2024 07:36:55 -0500 Subject: [PATCH 04/63] diagnostics: Handle TypeError when copying results Display and log an error, including contents of current_results. Clear the contents of current_results. Tests: - View the diagnostics results as normal. - Introduce a TypeError before the results are copied. See the error message shown in the interface. (The error details are cleared when the page is refreshed.) Helps: #2410 Signed-off-by: James Valleroy [sunil: Fix a mypy error] Signed-off-by: Sunil Mohan Adapa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/diagnostics/__init__.py | 20 ++++++++++++++++---- plinth/modules/diagnostics/views.py | 4 ++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/plinth/modules/diagnostics/__init__.py b/plinth/modules/diagnostics/__init__.py index cdef381a5..16180b5a8 100644 --- a/plinth/modules/diagnostics/__init__.py +++ b/plinth/modules/diagnostics/__init__.py @@ -103,7 +103,8 @@ def _run_on_all_enabled_modules(): current_results = { 'apps': [], 'results': collections.OrderedDict(), - 'progress_percentage': 0 + 'progress_percentage': 0, + 'exception': None, } for app in app_module.App.list(): @@ -335,15 +336,26 @@ def are_results_available(): return bool(results) -def get_results(): +def get_results() -> dict: """Return the latest results of full diagnostics.""" + global current_results + with results_lock: - results = deepcopy(current_results) + try: + results = deepcopy(current_results) + except TypeError as error: + # See #2410: cannot pickle 'dict_values' object + logger.error('Cannot get diagnostic results: %s - %s', error, + current_results) + exception = str(error) + ' - ' + str(current_results) + # Clear the results that can't be used. + current_results = {} + return {'exception': exception} # If no results are available in memory, then load from database. if not results: results = kvstore.get_default('diagnostics_results', '{}') - results = json.loads(results, cls=CheckJSONDecoder) + results = json.loads(str(results), cls=CheckJSONDecoder) results = {'results': results, 'progress_percentage': 100} # Add a translated name for each app diff --git a/plinth/modules/diagnostics/views.py b/plinth/modules/diagnostics/views.py index c9bd1ab8b..6a9437631 100644 --- a/plinth/modules/diagnostics/views.py +++ b/plinth/modules/diagnostics/views.py @@ -75,6 +75,10 @@ class DiagnosticsFullView(TemplateView): context['is_task_running'] = is_task_running context['results'] = diagnostics.get_results() context['refresh_page_sec'] = 3 if is_task_running else None + exception = context['results'].pop('exception', None) + if exception: + messages.error(self.request, exception) + return context From 526a3018e4ceb5ab9354900c2ebb1c40cad2d0c0 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 29 Feb 2024 18:28:26 -0800 Subject: [PATCH 05/63] users: Fix creating users with initial set of groups Fixes: #2409. When creating a user if one or more groups is selected, creation fails. This is because the fields contains group choices as (name, label) tuples instead of (group_id, label) tuples as expected by the many-to-many field mapping mechanism in ModelField class. Fix this by using the same mechanism used in UserUpdateForm, which is to reuse the base class form field (but adjust some properties). Tests: - During first boot - Django groups are fully created when form is accessed with blank database - In user creation/modify form: - Label appears are 'Permissions' - Choices appear fully and as 'Description (Group name)' - Help text is correct. - Choices are sorted on group name. - Django groups are fully created when form is accessed when a new group is added to code. - User can have no groups - Widget is multiple checkbox widget. Multiple groups can be selected. - User is added to proper ldap groups after submission - In user modify form: - If the user is last admin user, admin checkbox is checked and disabled. - Current list of groups is accurate shown when form is displayed. - Add remove of groups works as expected - Functional tests for gitweb and users apps pass Signed-off-by: Sunil Mohan Adapa Reviewed-by: Veiko Aasa --- plinth/modules/users/forms.py | 94 +++++++++++++++++------------ plinth/tests/functional/__init__.py | 3 +- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py index 41df46aa1..dea81f95e 100644 --- a/plinth/modules/users/forms.py +++ b/plinth/modules/users/forms.py @@ -50,6 +50,49 @@ class ValidNewUsernameCheckMixin: return True +class GroupsFieldMixin: + """Mixin to set common properties for the group field.""" + + def __init__(self, *args, **kwargs): + """Set basic properties for the groups field. + + Also ensure that all the groups are created in django. + """ + group_choices = dict(UsersAndGroups.get_group_choices()) + for group in group_choices: + Group.objects.get_or_create(name=group) + + super().__init__(*args, **kwargs) + + choices = [] + django_groups = sorted(self.fields['groups'].choices, + key=lambda choice: choice[1]) + for group_id, group_name in django_groups: + try: + group_id = group_id.value + except AttributeError: + pass + + # Show choices only from groups declared by apps. + if group_name in group_choices: + label = group_choices[group_name] + if group_name == 'admin' and self.is_last_admin_user: + label = {'label': label, 'disabled': True} + + choices.append((group_id, label)) + + self.fields['groups'].label = _('Permissions') + self.fields['groups'].choices = choices + self.fields['groups'].help_text = _( + '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).') + + @deconstructible class UsernameValidator(validators.RegexValidator): """Username validator. @@ -96,7 +139,7 @@ class PasswordConfirmForm(forms.Form): return confirm_password -class CreateUserForm(ValidNewUsernameCheckMixin, +class CreateUserForm(ValidNewUsernameCheckMixin, GroupsFieldMixin, plinth.forms.LanguageSelectionFormMixin, PasswordConfirmForm, UserCreationForm): """Custom user create form. @@ -105,17 +148,6 @@ class CreateUserForm(ValidNewUsernameCheckMixin, """ username = USERNAME_FIELD - groups = forms.MultipleChoiceField( - choices=UsersAndGroups.get_group_choices, - label=gettext_lazy('Permissions'), required=False, - widget=plinth.forms.CheckboxSelectMultiple, help_text=gettext_lazy( - '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).')) language = plinth.forms.LanguageSelectionFormMixin.language @@ -124,10 +156,14 @@ class CreateUserForm(ValidNewUsernameCheckMixin, fields = ('username', 'password1', 'password2', 'groups', 'language', 'confirm_password') + widgets = { + 'groups': plinth.forms.CheckboxSelectMultiple(), + } def __init__(self, request, *args, **kwargs): """Initialize the form with extra request argument.""" self.request = request + self.is_last_admin_user = False super().__init__(*args, **kwargs) self.fields['username'].widget.attrs.update({ 'autofocus': 'autofocus', @@ -140,6 +176,8 @@ class CreateUserForm(ValidNewUsernameCheckMixin, user = super().save(commit) if commit: + self.save_m2m() # Django 3.x does not call save_m2m() + user.userprofile.language = self.cleaned_data['language'] user.userprofile.save() auth_username = self.request.user.username @@ -155,7 +193,8 @@ class CreateUserForm(ValidNewUsernameCheckMixin, _('Creating LDAP user failed: {error}'.format( error=error))) - for group in self.cleaned_data['groups']: + groups = user.groups.values_list('name', flat=True) + for group in groups: try: privileged.add_user_to_group(user.get_username(), group, auth_username, @@ -173,7 +212,8 @@ class CreateUserForm(ValidNewUsernameCheckMixin, class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, - plinth.forms.LanguageSelectionFormMixin, forms.ModelForm): + GroupsFieldMixin, plinth.forms.LanguageSelectionFormMixin, + forms.ModelForm): """When user info is changed, also updates LDAP user.""" username = USERNAME_FIELD @@ -200,39 +240,15 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, def __init__(self, request, username, *args, **kwargs): """Initialize the form with extra request argument.""" - group_choices = dict(UsersAndGroups.get_group_choices()) - for group in group_choices: - Group.objects.get_or_create(name=group) - self.request = request self.username = username - super().__init__(*args, **kwargs) self.is_last_admin_user = get_last_admin_user() == self.username + super().__init__(*args, **kwargs) self.fields['username'].widget.attrs.update({ 'autocapitalize': 'none', 'autocomplete': 'username' }) - choices = [] - django_groups = sorted(self.fields['groups'].choices, - key=lambda choice: choice[1]) - for group_id, group_name in django_groups: - try: - group_id = group_id.value - except AttributeError: - pass - - # Show choices only from groups declared by apps. - if group_name in group_choices: - label = group_choices[group_name] - if group_name == 'admin' and self.is_last_admin_user: - label = {'label': label, 'disabled': True} - - choices.append((group_id, label)) - - self.fields['groups'].label = _('Permissions') - self.fields['groups'].choices = choices - if not is_user_admin(request): self.fields['is_active'].widget = forms.HiddenInput() self.fields['groups'].disabled = True diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index d2a6dcc51..2f86dae3a 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -614,7 +614,8 @@ def create_user(browser, name, password=None, groups=[]): browser.find_by_id('id_password2').fill(password) for group in groups: - browser.find_by_id(f'id_groups_{group}').check() + browser.find_by_xpath( + f'//label[contains(text(), "({group})")]/input').check() browser.find_by_id('id_confirm_password').fill( config['DEFAULT']['password']) From b36d4419c4f9b5b08d0f414130f9e82cf808e2d4 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 1 Mar 2024 08:54:00 -0800 Subject: [PATCH 06/63] users: Minor refactor when creating django groups Signed-off-by: Sunil Mohan Adapa Reviewed-by: Veiko Aasa --- plinth/modules/users/forms.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py index dea81f95e..4abc8bcf8 100644 --- a/plinth/modules/users/forms.py +++ b/plinth/modules/users/forms.py @@ -50,6 +50,15 @@ class ValidNewUsernameCheckMixin: return True +def _create_django_groups(): + """Ensure that all groups are present in the Django's group table.""" + group_choices = UsersAndGroups.get_group_choices() + for group_name, _label in group_choices: + Group.objects.get_or_create(name=group_name) + + return group_choices + + class GroupsFieldMixin: """Mixin to set common properties for the group field.""" @@ -58,9 +67,7 @@ class GroupsFieldMixin: Also ensure that all the groups are created in django. """ - group_choices = dict(UsersAndGroups.get_group_choices()) - for group in group_choices: - Group.objects.get_or_create(name=group) + groups_dict = dict(_create_django_groups()) super().__init__(*args, **kwargs) @@ -74,8 +81,8 @@ class GroupsFieldMixin: pass # Show choices only from groups declared by apps. - if group_name in group_choices: - label = group_choices[group_name] + if group_name in groups_dict: + label = groups_dict[group_name] if group_name == 'admin' and self.is_last_admin_user: label = {'label': label, 'disabled': True} @@ -399,9 +406,7 @@ class FirstBootForm(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm): _('Failed to add new user to admin group: {error}'.format( error=error))) - # Create initial Django groups - for group_choice in UsersAndGroups.get_group_choices(): - auth.models.Group.objects.get_or_create(name=group_choice[0]) + _create_django_groups() admin_group = auth.models.Group.objects.get(name='admin') admin_group.user_set.add(user) From ca0479aae2505af880668da02b44857bdb585312 Mon Sep 17 00:00:00 2001 From: Veiko Aasa Date: Fri, 8 Mar 2024 13:15:36 +0200 Subject: [PATCH 07/63] users: tests: Do not remove LDAP user when testing views Fixes an issue where the LDAP user 'tester' was removed after testing test_views.py. It happened when there were two admin users present. Tested with both stable and testing containers that all the users module tests pass and a user 'tester' is not removed when two admin users exists. Signed-off-by: Veiko Aasa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/users/tests/test_views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plinth/modules/users/tests/test_views.py b/plinth/modules/users/tests/test_views.py index ec4751beb..c0672b053 100644 --- a/plinth/modules/users/tests/test_views.py +++ b/plinth/modules/users/tests/test_views.py @@ -52,7 +52,8 @@ def module_patch(): patch(f'{privileged}.get_group_users') as get_group_users, \ patch('plinth.modules.ssh.privileged.set_keys'), \ patch('plinth.modules.ssh.privileged.get_keys') as get_keys, \ - patch(f'{privileged}.get_user_groups') as get_user_groups: + patch(f'{privileged}.get_user_groups') as get_user_groups, \ + patch(f'{privileged}.remove_user'): get_group_users.return_value = ['admin'] get_keys.return_value = [] get_user_groups.return_value = [] From 15b537ccb7cbb5079fe6fec17bf144935f86bd13 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 1 Mar 2024 20:08:04 -0800 Subject: [PATCH 08/63] log: Don't log with in color inside actions scripts This would be better for collecting the stderr of the action and logging it again. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/log.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plinth/log.py b/plinth/log.py index 5b5b7974f..69199c5d2 100644 --- a/plinth/log.py +++ b/plinth/log.py @@ -76,7 +76,9 @@ def action_init(): """Initialize logging for action scripts.""" _capture_warnings() - logging.config.dictConfig(get_configuration()) + configuration = get_configuration() + del configuration['handlers']['console']['formatter'] + logging.config.dictConfig(configuration) def init(): From 1274ffdf879537f2ec13ee71b98d04693c0af179 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 1 Mar 2024 20:09:25 -0800 Subject: [PATCH 09/63] actions: Fix log message when action return can't be decoded return_value is not available during exception handling. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/actions.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plinth/actions.py b/plinth/actions.py index b98eebab2..a9e7b7cb1 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -134,9 +134,8 @@ def _wait_for_return(module_name, action_name, args, kwargs, log_error, proc, try: return_value = json.loads(b''.join(buffers)) except json.JSONDecodeError: - logger.error( - 'Error decoding action return value %s..%s(*%s, **%s): %s', - module_name, action_name, args, kwargs, return_value) + logger.error('Error decoding action return value %s..%s(*%s, **%s)', + module_name, action_name, args, kwargs) raise if return_value['result'] == 'success': From 3a7dd4e812e9c977a6a88f897dfbca485c425cfc Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 1 Mar 2024 20:10:50 -0800 Subject: [PATCH 10/63] actions: When action errors out, log a better message Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/actions.py | 44 +++++++++++++++++++++++++++++++++--- plinth/tests/test_actions.py | 2 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/plinth/actions.py b/plinth/actions.py index a9e7b7cb1..187a0bd0b 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -146,13 +146,51 @@ def _wait_for_return(module_name, action_name, args, kwargs, log_error, proc, exception = exception_class(*return_value['exception']['args'], output, error) if log_error: - logger.error('Error running action %s..%s(*%s, **%s): %s %s %s', - module_name, action_name, args, kwargs, exception, - exception.args, return_value['exception']['traceback']) + _log_error(module_name, action_name, args, kwargs, exception, + return_value) raise exception +def _log_error(module_name, action_name, args, kwargs, exception, + return_value): + """Log the exception in a readable manner.""" + args = [json.dumps(arg) for arg in args] + kwargs = [f'{key}=' + json.dumps(value) for key, value in kwargs.items()] + full_args = ', '.join(args + kwargs) + exception_args = ', '.join( + [json.dumps(arg) for arg in exception.args[:-2]]) + + stdout = exception.args[-2].decode() + if stdout: + lines = stdout.split('\n') + lines = lines[:-1] if not lines[-1] else lines + stdout = '\n'.join(('│ ' + line for line in lines)) + stdout = 'Stdout:\n' + stdout + '\n' + + stderr = exception.args[-1].decode() + if stderr: + lines = stderr.split('\n') + lines = lines[:-1] if not lines[-1] else lines + stderr = '\n'.join(('║ ' + line for line in lines)) + stderr = 'Stderr:\n' + stderr + '\n' + + traceback = return_value['exception']['traceback'] + if traceback: + all_lines = [] + for entry in traceback: + lines = entry.split('\n') + all_lines += lines[:-1] if not lines[-1] else lines + + traceback = '\n'.join(('╞ ' + line for line in all_lines)) + traceback = 'Action traceback:\n' + traceback + '\n' + + logger.error('Error running action %s..%s(%s): %s(%s)\n' + '%s%s%s', module_name, action_name, full_args, + exception.__class__.__name__, exception_args, stdout, stderr, + traceback) + + def _thread_reader(read_fd, buffers): """Read from the pipe in a separate thread.""" while True: diff --git a/plinth/tests/test_actions.py b/plinth/tests/test_actions.py index ed37a750e..4a1f1dc1d 100644 --- a/plinth/tests/test_actions.py +++ b/plinth/tests/test_actions.py @@ -32,7 +32,7 @@ def fixture_popen(): popen.called_with_write_fd.append(write_fd) os.write(write_fd, bytes(popen.return_value, encoding='utf-8')) proc = Mock() - proc.communicate.return_value = ('', '') + proc.communicate.return_value = (b'', b'') proc.returncode = 0 return proc From f9b186e14f7a68ff9bd3c2a0e750537b22be1df5 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 4 Mar 2024 19:49:15 -0800 Subject: [PATCH 11/63] *: Add type hints for app init methods - This is so that the methods will be checked by mypy. This should help identify any incorrect initialization of components. - Remove unused self.repos in GitwebApp. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/app.py | 4 ++-- plinth/modules/apache/__init__.py | 6 +++--- plinth/modules/api/__init__.py | 2 +- plinth/modules/avahi/__init__.py | 2 +- plinth/modules/backups/__init__.py | 2 +- plinth/modules/bepasty/__init__.py | 2 +- plinth/modules/bind/__init__.py | 2 +- plinth/modules/calibre/__init__.py | 2 +- plinth/modules/cockpit/__init__.py | 2 +- plinth/modules/config/__init__.py | 2 +- plinth/modules/coturn/__init__.py | 2 +- plinth/modules/datetime/__init__.py | 8 ++++---- plinth/modules/deluge/__init__.py | 2 +- plinth/modules/diagnostics/__init__.py | 2 +- plinth/modules/dynamicdns/__init__.py | 2 +- plinth/modules/ejabberd/__init__.py | 2 +- plinth/modules/email/__init__.py | 2 +- plinth/modules/firewall/__init__.py | 2 +- plinth/modules/first_boot/__init__.py | 2 +- plinth/modules/gitweb/__init__.py | 4 +--- plinth/modules/help/__init__.py | 2 +- plinth/modules/i2p/__init__.py | 2 +- plinth/modules/ikiwiki/__init__.py | 2 +- plinth/modules/infinoted/__init__.py | 2 +- plinth/modules/janus/__init__.py | 2 +- plinth/modules/jsxc/__init__.py | 2 +- plinth/modules/kiwix/__init__.py | 2 +- plinth/modules/letsencrypt/__init__.py | 2 +- plinth/modules/matrixsynapse/__init__.py | 2 +- plinth/modules/mediawiki/__init__.py | 2 +- plinth/modules/minetest/__init__.py | 2 +- plinth/modules/minidlna/__init__.py | 2 +- plinth/modules/mumble/__init__.py | 2 +- plinth/modules/names/__init__.py | 2 +- plinth/modules/networks/__init__.py | 2 +- plinth/modules/openvpn/__init__.py | 2 +- plinth/modules/pagekite/__init__.py | 2 +- plinth/modules/performance/__init__.py | 2 +- plinth/modules/power/__init__.py | 2 +- plinth/modules/privacy/__init__.py | 2 +- plinth/modules/privoxy/__init__.py | 2 +- plinth/modules/quassel/__init__.py | 2 +- plinth/modules/radicale/__init__.py | 2 +- plinth/modules/roundcube/__init__.py | 2 +- plinth/modules/rssbridge/__init__.py | 2 +- plinth/modules/samba/__init__.py | 2 +- plinth/modules/searx/__init__.py | 2 +- plinth/modules/security/__init__.py | 2 +- plinth/modules/shaarli/__init__.py | 2 +- plinth/modules/shadowsocks/__init__.py | 2 +- plinth/modules/shadowsocksserver/__init__.py | 2 +- plinth/modules/sharing/__init__.py | 2 +- plinth/modules/snapshot/__init__.py | 2 +- plinth/modules/ssh/__init__.py | 2 +- plinth/modules/sso/__init__.py | 2 +- plinth/modules/storage/__init__.py | 2 +- plinth/modules/syncthing/__init__.py | 2 +- plinth/modules/tor/__init__.py | 2 +- plinth/modules/torproxy/__init__.py | 2 +- plinth/modules/transmission/__init__.py | 2 +- plinth/modules/ttrss/__init__.py | 2 +- plinth/modules/upgrades/__init__.py | 2 +- plinth/modules/users/__init__.py | 2 +- plinth/modules/wireguard/__init__.py | 2 +- plinth/modules/wordpress/__init__.py | 2 +- plinth/modules/zoph/__init__.py | 2 +- 66 files changed, 72 insertions(+), 74 deletions(-) diff --git a/plinth/app.py b/plinth/app.py index 17927270f..c7e74548a 100644 --- a/plinth/app.py +++ b/plinth/app.py @@ -58,7 +58,7 @@ class App: NEEDS_UPDATE = 'needs-update' UP_TO_DATE = 'up-to-date' - def __init__(self): + def __init__(self) -> None: """Build the app by adding components. App may be built just for the purpose for querying. For example, when @@ -71,7 +71,7 @@ class App: if not self.app_id: raise ValueError('Invalid app ID configured') - self.components = collections.OrderedDict() + self.components: dict[str, Component] = collections.OrderedDict() # Add self to global list of apps self._all_apps[self.app_id] = self diff --git a/plinth/modules/apache/__init__.py b/plinth/modules/apache/__init__.py index d5ead948b..ba8bd67af 100644 --- a/plinth/modules/apache/__init__.py +++ b/plinth/modules/apache/__init__.py @@ -24,7 +24,7 @@ class ApacheApp(app_module.App): _version = 12 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() @@ -61,8 +61,8 @@ class ApacheApp(app_module.App): daemon = Daemon('daemon-apache', 'apache2') self.add(daemon) - daemon = RelatedDaemon('related-daemon-apache', 'uwsgi') - self.add(daemon) + related_daemon = RelatedDaemon('related-daemon-apache', 'uwsgi') + self.add(related_daemon) def setup(self, old_version): """Install and configure the app.""" diff --git a/plinth/modules/api/__init__.py b/plinth/modules/api/__init__.py index 153718faf..261d3ec06 100644 --- a/plinth/modules/api/__init__.py +++ b/plinth/modules/api/__init__.py @@ -13,7 +13,7 @@ class ApiApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/avahi/__init__.py b/plinth/modules/avahi/__init__.py index 420b4153b..33c33ea49 100644 --- a/plinth/modules/avahi/__init__.py +++ b/plinth/modules/avahi/__init__.py @@ -38,7 +38,7 @@ class AvahiApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py index 3cee6898c..1944ce64c 100644 --- a/plinth/modules/backups/__init__.py +++ b/plinth/modules/backups/__init__.py @@ -35,7 +35,7 @@ class BackupsApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/bepasty/__init__.py b/plinth/modules/bepasty/__init__.py index 784650814..09c199a3e 100644 --- a/plinth/modules/bepasty/__init__.py +++ b/plinth/modules/bepasty/__init__.py @@ -50,7 +50,7 @@ class BepastyApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/bind/__init__.py b/plinth/modules/bind/__init__.py index 0f4c6449d..37c52b6df 100644 --- a/plinth/modules/bind/__init__.py +++ b/plinth/modules/bind/__init__.py @@ -32,7 +32,7 @@ class BindApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/calibre/__init__.py b/plinth/modules/calibre/__init__.py index dd5558e05..a04792a88 100644 --- a/plinth/modules/calibre/__init__.py +++ b/plinth/modules/calibre/__init__.py @@ -46,7 +46,7 @@ class CalibreApp(app_module.App): DAEMON = 'calibre-server-freedombox' - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/cockpit/__init__.py b/plinth/modules/cockpit/__init__.py index 9bc16d059..7d39c4d55 100644 --- a/plinth/modules/cockpit/__init__.py +++ b/plinth/modules/cockpit/__init__.py @@ -44,7 +44,7 @@ class CockpitApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/config/__init__.py b/plinth/modules/config/__init__.py index 293168da2..8a79e4666 100644 --- a/plinth/modules/config/__init__.py +++ b/plinth/modules/config/__init__.py @@ -35,7 +35,7 @@ class ConfigApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() info = app_module.Info(app_id=self.app_id, version=self._version, diff --git a/plinth/modules/coturn/__init__.py b/plinth/modules/coturn/__init__.py index 1eebd4c34..133511ac7 100644 --- a/plinth/modules/coturn/__init__.py +++ b/plinth/modules/coturn/__init__.py @@ -44,7 +44,7 @@ class CoturnApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/datetime/__init__.py b/plinth/modules/datetime/__init__.py index 2a8e7b397..743385c70 100644 --- a/plinth/modules/datetime/__init__.py +++ b/plinth/modules/datetime/__init__.py @@ -60,7 +60,7 @@ class DateTimeApp(app_module.App): return self._time_managed - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() @@ -77,9 +77,9 @@ class DateTimeApp(app_module.App): packages = Packages('packages-datetime', ['systemd-timesyncd']) self.add(packages) - daemon = RelatedDaemon('daemon-datetime-timedated', - 'systemd-timedated') - self.add(daemon) + related_daemon = RelatedDaemon('daemon-datetime-timedated', + 'systemd-timedated') + self.add(related_daemon) if self._is_time_managed(): daemon = Daemon('daemon-datetime', 'systemd-timesyncd') diff --git a/plinth/modules/deluge/__init__.py b/plinth/modules/deluge/__init__.py index 385abe2c5..deec8588e 100644 --- a/plinth/modules/deluge/__init__.py +++ b/plinth/modules/deluge/__init__.py @@ -33,7 +33,7 @@ class DelugeApp(app_module.App): _version = 8 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/diagnostics/__init__.py b/plinth/modules/diagnostics/__init__.py index 16180b5a8..64992bf05 100644 --- a/plinth/modules/diagnostics/__init__.py +++ b/plinth/modules/diagnostics/__init__.py @@ -44,7 +44,7 @@ class DiagnosticsApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() info = app_module.Info(app_id=self.app_id, version=self._version, diff --git a/plinth/modules/dynamicdns/__init__.py b/plinth/modules/dynamicdns/__init__.py index 97053fa22..c257e246b 100644 --- a/plinth/modules/dynamicdns/__init__.py +++ b/plinth/modules/dynamicdns/__init__.py @@ -52,7 +52,7 @@ class DynamicDNSApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/ejabberd/__init__.py b/plinth/modules/ejabberd/__init__.py index d4489c7a1..d11fe1983 100644 --- a/plinth/modules/ejabberd/__init__.py +++ b/plinth/modules/ejabberd/__init__.py @@ -52,7 +52,7 @@ class EjabberdApp(app_module.App): _version = 8 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/email/__init__.py b/plinth/modules/email/__init__.py index 947f45d63..5c28538da 100644 --- a/plinth/modules/email/__init__.py +++ b/plinth/modules/email/__init__.py @@ -55,7 +55,7 @@ class EmailApp(plinth.app.App): _version = 4 - def __init__(self): + def __init__(self) -> None: """Initialize the email app.""" super().__init__() diff --git a/plinth/modules/firewall/__init__.py b/plinth/modules/firewall/__init__.py index 3cd45ea7c..9de569029 100644 --- a/plinth/modules/firewall/__init__.py +++ b/plinth/modules/firewall/__init__.py @@ -53,7 +53,7 @@ class FirewallApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/first_boot/__init__.py b/plinth/modules/first_boot/__init__.py index a608f569d..bf3877710 100644 --- a/plinth/modules/first_boot/__init__.py +++ b/plinth/modules/first_boot/__init__.py @@ -39,7 +39,7 @@ class FirstBootApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/gitweb/__init__.py b/plinth/modules/gitweb/__init__.py index 3d8599217..78c34ecf5 100644 --- a/plinth/modules/gitweb/__init__.py +++ b/plinth/modules/gitweb/__init__.py @@ -38,14 +38,12 @@ class GitwebApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() groups = {'git-access': _('Read-write access to Git repositories')} - self.repos = [] - info = app_module.Info(app_id=self.app_id, version=self._version, name=_('Gitweb'), icon_filename='gitweb', short_description=_('Simple Git Hosting'), diff --git a/plinth/modules/help/__init__.py b/plinth/modules/help/__init__.py index 0acfa765f..e634df881 100644 --- a/plinth/modules/help/__init__.py +++ b/plinth/modules/help/__init__.py @@ -22,7 +22,7 @@ class HelpApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/i2p/__init__.py b/plinth/modules/i2p/__init__.py index b9f94f91f..acd89bcdf 100644 --- a/plinth/modules/i2p/__init__.py +++ b/plinth/modules/i2p/__init__.py @@ -42,7 +42,7 @@ class I2PApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/ikiwiki/__init__.py b/plinth/modules/ikiwiki/__init__.py index 3c81712f9..3d498fdea 100644 --- a/plinth/modules/ikiwiki/__init__.py +++ b/plinth/modules/ikiwiki/__init__.py @@ -37,7 +37,7 @@ class IkiwikiApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/infinoted/__init__.py b/plinth/modules/infinoted/__init__.py index aa0b6f884..00f98e69c 100644 --- a/plinth/modules/infinoted/__init__.py +++ b/plinth/modules/infinoted/__init__.py @@ -33,7 +33,7 @@ class InfinotedApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/janus/__init__.py b/plinth/modules/janus/__init__.py index 74428d3cd..3c4dafac2 100644 --- a/plinth/modules/janus/__init__.py +++ b/plinth/modules/janus/__init__.py @@ -35,7 +35,7 @@ class JanusApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/jsxc/__init__.py b/plinth/modules/jsxc/__init__.py index 39194eef4..2f66bdcd8 100644 --- a/plinth/modules/jsxc/__init__.py +++ b/plinth/modules/jsxc/__init__.py @@ -30,7 +30,7 @@ class JSXCApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/kiwix/__init__.py b/plinth/modules/kiwix/__init__.py index 012ef534b..eaa439a12 100644 --- a/plinth/modules/kiwix/__init__.py +++ b/plinth/modules/kiwix/__init__.py @@ -46,7 +46,7 @@ class KiwixApp(app_module.App): DAEMON = 'kiwix-server-freedombox' - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/letsencrypt/__init__.py b/plinth/modules/letsencrypt/__init__.py index 7098690a5..ab42b18f6 100644 --- a/plinth/modules/letsencrypt/__init__.py +++ b/plinth/modules/letsencrypt/__init__.py @@ -51,7 +51,7 @@ class LetsEncryptApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/matrixsynapse/__init__.py b/plinth/modules/matrixsynapse/__init__.py index 9078111d5..dc1292081 100644 --- a/plinth/modules/matrixsynapse/__init__.py +++ b/plinth/modules/matrixsynapse/__init__.py @@ -46,7 +46,7 @@ class MatrixSynapseApp(app_module.App): _version = 10 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/mediawiki/__init__.py b/plinth/modules/mediawiki/__init__.py index 1bec60eea..ab1802578 100644 --- a/plinth/modules/mediawiki/__init__.py +++ b/plinth/modules/mediawiki/__init__.py @@ -42,7 +42,7 @@ class MediaWikiApp(app_module.App): _version = 12 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() self._private_mode = True diff --git a/plinth/modules/minetest/__init__.py b/plinth/modules/minetest/__init__.py index e3f44c204..fe08ad228 100644 --- a/plinth/modules/minetest/__init__.py +++ b/plinth/modules/minetest/__init__.py @@ -48,7 +48,7 @@ class MinetestApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/minidlna/__init__.py b/plinth/modules/minidlna/__init__.py index 6cc2c6a1b..edf97e245 100644 --- a/plinth/modules/minidlna/__init__.py +++ b/plinth/modules/minidlna/__init__.py @@ -37,7 +37,7 @@ class MiniDLNAApp(app_module.App): _version = 5 - def __init__(self): + def __init__(self) -> None: """Initialize the app components.""" super().__init__() diff --git a/plinth/modules/mumble/__init__.py b/plinth/modules/mumble/__init__.py index b18ce5d4d..e43f26be7 100644 --- a/plinth/modules/mumble/__init__.py +++ b/plinth/modules/mumble/__init__.py @@ -37,7 +37,7 @@ class MumbleApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/names/__init__.py b/plinth/modules/names/__init__.py index f06913e77..e6cf29247 100644 --- a/plinth/modules/names/__init__.py +++ b/plinth/modules/names/__init__.py @@ -36,7 +36,7 @@ class NamesApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() info = app_module.Info(app_id=self.app_id, version=self._version, diff --git a/plinth/modules/networks/__init__.py b/plinth/modules/networks/__init__.py index d231b832e..e793dddb0 100644 --- a/plinth/modules/networks/__init__.py +++ b/plinth/modules/networks/__init__.py @@ -50,7 +50,7 @@ class NetworksApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/openvpn/__init__.py b/plinth/modules/openvpn/__init__.py index 542975692..5a41ea820 100644 --- a/plinth/modules/openvpn/__init__.py +++ b/plinth/modules/openvpn/__init__.py @@ -36,7 +36,7 @@ class OpenVPNApp(app_module.App): _version = 5 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/pagekite/__init__.py b/plinth/modules/pagekite/__init__.py index c9df15ec2..29e6b313f 100644 --- a/plinth/modules/pagekite/__init__.py +++ b/plinth/modules/pagekite/__init__.py @@ -50,7 +50,7 @@ class PagekiteApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/performance/__init__.py b/plinth/modules/performance/__init__.py index 0d79fee77..4b681e1ec 100644 --- a/plinth/modules/performance/__init__.py +++ b/plinth/modules/performance/__init__.py @@ -32,7 +32,7 @@ class PerformanceApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/power/__init__.py b/plinth/modules/power/__init__.py index 60ae0dcdc..f80a936bd 100644 --- a/plinth/modules/power/__init__.py +++ b/plinth/modules/power/__init__.py @@ -23,7 +23,7 @@ class PowerApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/privacy/__init__.py b/plinth/modules/privacy/__init__.py index 742c8758c..56170c12e 100644 --- a/plinth/modules/privacy/__init__.py +++ b/plinth/modules/privacy/__init__.py @@ -24,7 +24,7 @@ class PrivacyApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/privoxy/__init__.py b/plinth/modules/privoxy/__init__.py index 364b11e52..72f83ea22 100644 --- a/plinth/modules/privoxy/__init__.py +++ b/plinth/modules/privoxy/__init__.py @@ -44,7 +44,7 @@ class PrivoxyApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/quassel/__init__.py b/plinth/modules/quassel/__init__.py index b6bcc06dc..ed59be865 100644 --- a/plinth/modules/quassel/__init__.py +++ b/plinth/modules/quassel/__init__.py @@ -43,7 +43,7 @@ class QuasselApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/radicale/__init__.py b/plinth/modules/radicale/__init__.py index c2b72ff79..70c7cdf2c 100644 --- a/plinth/modules/radicale/__init__.py +++ b/plinth/modules/radicale/__init__.py @@ -45,7 +45,7 @@ class RadicaleApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/roundcube/__init__.py b/plinth/modules/roundcube/__init__.py index fbcf2f018..0268208ff 100644 --- a/plinth/modules/roundcube/__init__.py +++ b/plinth/modules/roundcube/__init__.py @@ -42,7 +42,7 @@ class RoundcubeApp(app_module.App): _version = 4 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/rssbridge/__init__.py b/plinth/modules/rssbridge/__init__.py index 49520a7a0..7126b5ac3 100644 --- a/plinth/modules/rssbridge/__init__.py +++ b/plinth/modules/rssbridge/__init__.py @@ -39,7 +39,7 @@ class RSSBridgeApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/samba/__init__.py b/plinth/modules/samba/__init__.py index ef2bee768..345e3ce6b 100644 --- a/plinth/modules/samba/__init__.py +++ b/plinth/modules/samba/__init__.py @@ -43,7 +43,7 @@ class SambaApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/searx/__init__.py b/plinth/modules/searx/__init__.py index 72e6a851d..f81e3375f 100644 --- a/plinth/modules/searx/__init__.py +++ b/plinth/modules/searx/__init__.py @@ -31,7 +31,7 @@ class SearxApp(app_module.App): _version = 6 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/security/__init__.py b/plinth/modules/security/__init__.py index ecaf38555..a9effe9b9 100644 --- a/plinth/modules/security/__init__.py +++ b/plinth/modules/security/__init__.py @@ -27,7 +27,7 @@ class SecurityApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/shaarli/__init__.py b/plinth/modules/shaarli/__init__.py index a6db3aa60..4559f2613 100644 --- a/plinth/modules/shaarli/__init__.py +++ b/plinth/modules/shaarli/__init__.py @@ -28,7 +28,7 @@ class ShaarliApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/shadowsocks/__init__.py b/plinth/modules/shadowsocks/__init__.py index 9707a87eb..57f26d4cb 100644 --- a/plinth/modules/shadowsocks/__init__.py +++ b/plinth/modules/shadowsocks/__init__.py @@ -42,7 +42,7 @@ class ShadowsocksApp(app_module.App): DAEMON = 'shadowsocks-libev-local@freedombox' - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/shadowsocksserver/__init__.py b/plinth/modules/shadowsocksserver/__init__.py index 01c237a0b..f574ca4e1 100644 --- a/plinth/modules/shadowsocksserver/__init__.py +++ b/plinth/modules/shadowsocksserver/__init__.py @@ -39,7 +39,7 @@ class ShadowsocksServerApp(app_module.App): DAEMON = 'shadowsocks-libev-server@fbxserver' - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/sharing/__init__.py b/plinth/modules/sharing/__init__.py index 0d43274cc..e6c1e4c5d 100644 --- a/plinth/modules/sharing/__init__.py +++ b/plinth/modules/sharing/__init__.py @@ -27,7 +27,7 @@ class SharingApp(app_module.App): _version = 3 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() info = app_module.Info(app_id=self.app_id, version=self._version, diff --git a/plinth/modules/snapshot/__init__.py b/plinth/modules/snapshot/__init__.py index 9c281aa9b..5e1c215e7 100644 --- a/plinth/modules/snapshot/__init__.py +++ b/plinth/modules/snapshot/__init__.py @@ -42,7 +42,7 @@ class SnapshotApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/ssh/__init__.py b/plinth/modules/ssh/__init__.py index f4144e619..d4a8438db 100644 --- a/plinth/modules/ssh/__init__.py +++ b/plinth/modules/ssh/__init__.py @@ -33,7 +33,7 @@ class SSHApp(app_module.App): _version = 4 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/sso/__init__.py b/plinth/modules/sso/__init__.py index 42753e7b3..20782d462 100644 --- a/plinth/modules/sso/__init__.py +++ b/plinth/modules/sso/__init__.py @@ -17,7 +17,7 @@ class SSOApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/storage/__init__.py b/plinth/modules/storage/__init__.py index 71cfce75e..4f7034193 100644 --- a/plinth/modules/storage/__init__.py +++ b/plinth/modules/storage/__init__.py @@ -37,7 +37,7 @@ class StorageApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/syncthing/__init__.py b/plinth/modules/syncthing/__init__.py index 2d18a525b..4c11317a6 100644 --- a/plinth/modules/syncthing/__init__.py +++ b/plinth/modules/syncthing/__init__.py @@ -47,7 +47,7 @@ class SyncthingApp(app_module.App): DAEMON = 'syncthing@syncthing' - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py index 541ff9e92..d72781b7b 100644 --- a/plinth/modules/tor/__init__.py +++ b/plinth/modules/tor/__init__.py @@ -53,7 +53,7 @@ class TorApp(app_module.App): _version = 7 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/torproxy/__init__.py b/plinth/modules/torproxy/__init__.py index 6e805bb7e..289be5fb6 100644 --- a/plinth/modules/torproxy/__init__.py +++ b/plinth/modules/torproxy/__init__.py @@ -47,7 +47,7 @@ class TorProxyApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/transmission/__init__.py b/plinth/modules/transmission/__init__.py index 5ecd1faad..4ad655571 100644 --- a/plinth/modules/transmission/__init__.py +++ b/plinth/modules/transmission/__init__.py @@ -62,7 +62,7 @@ class TransmissionApp(app_module.App): DAEMON = 'transmission-daemon' - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/ttrss/__init__.py b/plinth/modules/ttrss/__init__.py index 9445fcf67..de9f53f3a 100644 --- a/plinth/modules/ttrss/__init__.py +++ b/plinth/modules/ttrss/__init__.py @@ -40,7 +40,7 @@ class TTRSSApp(app_module.App): _version = 6 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/upgrades/__init__.py b/plinth/modules/upgrades/__init__.py index 9685ce5a6..82279d3f1 100644 --- a/plinth/modules/upgrades/__init__.py +++ b/plinth/modules/upgrades/__init__.py @@ -57,7 +57,7 @@ class UpgradesApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py index b97bf28a0..c9774b405 100644 --- a/plinth/modules/users/__init__.py +++ b/plinth/modules/users/__init__.py @@ -50,7 +50,7 @@ class UsersApp(app_module.App): can_be_disabled = False - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/wireguard/__init__.py b/plinth/modules/wireguard/__init__.py index 49297e1e4..043db2aba 100644 --- a/plinth/modules/wireguard/__init__.py +++ b/plinth/modules/wireguard/__init__.py @@ -39,7 +39,7 @@ class WireguardApp(app_module.App): _version = 1 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/wordpress/__init__.py b/plinth/modules/wordpress/__init__.py index 668e2c9c9..91d24de24 100644 --- a/plinth/modules/wordpress/__init__.py +++ b/plinth/modules/wordpress/__init__.py @@ -45,7 +45,7 @@ class WordPressApp(app_module.App): _version = 4 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() diff --git a/plinth/modules/zoph/__init__.py b/plinth/modules/zoph/__init__.py index 3f6297c19..b5bbd75f0 100644 --- a/plinth/modules/zoph/__init__.py +++ b/plinth/modules/zoph/__init__.py @@ -46,7 +46,7 @@ class ZophApp(app_module.App): _version = 2 - def __init__(self): + def __init__(self) -> None: """Create components for the app.""" super().__init__() From 4b09d91f93c7e7222bb5d6e22244cbbcbb4c542e Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Tue, 5 Mar 2024 08:58:25 -0800 Subject: [PATCH 12/63] *: Add type hints for diagnose method Helps: #2410. - Ensure that diagnostics methods and parameters are type checked so that we can catch any potential issues. - Move plinth/modules/diagnostics/check.py to plinth/diagnostic_check.py to avoid many circular dependencies created. This is due to plinth.modules.diagnostics automatically imported when plinth.modules.diagnostics.check is imported. Also app.py is already (type) dependent on diagnostic_check due to diagnose() method. To make the Check classes independent of diagnostic module is okay. Tests: - Run make check-type. - Run full diagnostics with following apps installed: torproxy, tor. - Test to netcat to 9051 in tor works. - Test 'port available for internal/external networks' in firewall works. - Test 'Package is latest' works. - Test 'Access url with proxy' in privoxy works. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy [jvalleroy: Also move tests for diagnostic_check] Signed-off-by: James Valleroy --- doc/dev/reference/components/index.rst | 4 +- plinth/action_utils.py | 6 +-- plinth/app.py | 14 ++--- plinth/config.py | 8 +-- plinth/daemon.py | 52 +++++++++++-------- .../check.py => diagnostic_check.py} | 5 +- plinth/modules/apache/components.py | 26 +++++++--- .../modules/apache/tests/test_components.py | 2 +- plinth/modules/datetime/__init__.py | 6 +-- plinth/modules/diagnostics/__init__.py | 5 +- plinth/modules/diagnostics/views.py | 2 +- plinth/modules/firewall/__init__.py | 13 +++-- plinth/modules/firewall/components.py | 16 ++++-- plinth/modules/firewall/privileged.py | 7 ++- .../modules/firewall/tests/test_components.py | 2 +- plinth/modules/letsencrypt/__init__.py | 4 +- plinth/modules/networks/__init__.py | 3 +- plinth/modules/privoxy/__init__.py | 9 ++-- plinth/modules/tor/__init__.py | 10 ++-- plinth/modules/torproxy/__init__.py | 8 +-- plinth/modules/users/__init__.py | 18 ++++--- plinth/modules/users/privileged.py | 2 +- plinth/package.py | 21 ++++---- plinth/tests/test_app.py | 4 +- plinth/tests/test_config.py | 2 +- plinth/tests/test_daemon.py | 22 ++++---- .../test_diagnostic_check.py} | 5 +- plinth/tests/test_package.py | 2 +- 28 files changed, 161 insertions(+), 117 deletions(-) rename plinth/{modules/diagnostics/check.py => diagnostic_check.py} (91%) rename plinth/{modules/diagnostics/tests/test_check.py => tests/test_diagnostic_check.py} (91%) diff --git a/doc/dev/reference/components/index.rst b/doc/dev/reference/components/index.rst index ad3fd9d97..0e523cba7 100644 --- a/doc/dev/reference/components/index.rst +++ b/doc/dev/reference/components/index.rst @@ -37,8 +37,8 @@ Base Classes Other Classes ^^^^^^^^^^^^^ -.. autoclass:: plinth.modules.diagnostics.check.DiagnosticCheck +.. autoclass:: plinth.diagnostic_check.DiagnosticCheck :members: -.. autoclass:: plinth.modules.diagnostics.check.Result +.. autoclass:: plinth.diagnostic_check.Result :members: diff --git a/plinth/action_utils.py b/plinth/action_utils.py index c3d6945f9..3e6bffaca 100644 --- a/plinth/action_utils.py +++ b/plinth/action_utils.py @@ -275,7 +275,7 @@ def uwsgi_disable(config_name): service_start('uwsgi') -def get_addresses(): +def get_addresses() -> list[dict[str, str | bool]]: """Return a list of IP addresses and hostnames.""" addresses = get_ip_addresses() @@ -309,14 +309,14 @@ def get_addresses(): return addresses -def get_ip_addresses(): +def get_ip_addresses() -> list[dict[str, str | bool]]: """Return a list of IP addresses assigned to the system.""" addresses = [] output = subprocess.check_output(['ip', '-o', 'addr']) for line in output.decode().splitlines(): parts = line.split() - address = { + address: dict[str, str | bool] = { 'kind': '4' if parts[2] == 'inet' else '6', 'address': parts[3].split('/')[0], 'url_address': parts[3].split('/')[0], diff --git a/plinth/app.py b/plinth/app.py index c7e74548a..6969720f1 100644 --- a/plinth/app.py +++ b/plinth/app.py @@ -7,9 +7,10 @@ import collections import enum import inspect import logging -from typing import ClassVar +from typing import ClassVar, TypeAlias from plinth import cfg +from plinth.diagnostic_check import DiagnosticCheck from plinth.signals import post_app_loading from . import clients as clients_module @@ -17,6 +18,8 @@ from . import db logger = logging.getLogger(__name__) +_list_type: TypeAlias = list + class App: """Implement common functionality for an app. @@ -208,11 +211,11 @@ class App: if not component.is_leader: component.set_enabled(enabled) - def diagnose(self): + def diagnose(self) -> _list_type[DiagnosticCheck]: """Run diagnostics and return results. Return value must be a list of results. Each result is a - :class:`~plinth.modules.diagnostics.check.DiagnosticCheck` with a + :class:`~plinth.diagnostic_check.DiagnosticCheck` with a unique check_id, a user visible description of the test, and the result. The test result is a string enumeration from 'failed', 'passed', 'error', 'warning' and 'not_done'. @@ -300,12 +303,11 @@ class Component: def disable(self): """Run operations to disable the component.""" - @staticmethod - def diagnose(): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return results. Return value must be a list of results. Each result is a - :class:`~plinth.modules.diagnostics.check.DiagnosticCheck` with a + :class:`~plinth.diagnostic_check.DiagnosticCheck` with a unique check_id, a user visible description of the test, and the result. The test result is a string enumeration from 'failed', 'passed', 'error', 'warning' and 'not_done'. diff --git a/plinth/config.py b/plinth/config.py index 1ab32cf0d..d274afd08 100644 --- a/plinth/config.py +++ b/plinth/config.py @@ -5,6 +5,8 @@ import pathlib from django.utils.translation import gettext_noop +from plinth.diagnostic_check import (DiagnosticCheck, + DiagnosticCheckParameters, Result) from plinth.privileged import config as privileged from . import app as app_module @@ -99,10 +101,8 @@ class DropinConfigs(app_module.FollowerComponent): for path in self.etc_paths: privileged.dropin_unlink(self.app_id, path, missing_ok=True) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Check all links/copies and return generate diagnostic results.""" - from plinth.modules.diagnostics.check import DiagnosticCheck, Result - results = [] for path in self.etc_paths: etc_path = self._get_etc_path(path) @@ -118,7 +118,7 @@ class DropinConfigs(app_module.FollowerComponent): result_string = Result.PASSED if result else Result.FAILED description = gettext_noop( 'Static configuration {etc_path} is setup properly') - parameters = {'etc_path': str(etc_path)} + parameters: DiagnosticCheckParameters = {'etc_path': str(etc_path)} results.append( DiagnosticCheck(check_id, description, result_string, parameters)) diff --git a/plinth/daemon.py b/plinth/daemon.py index 24844f1be..dad74d8d0 100644 --- a/plinth/daemon.py +++ b/plinth/daemon.py @@ -8,13 +8,17 @@ import psutil from django.utils.translation import gettext_noop from plinth import action_utils, app +from plinth.diagnostic_check import (DiagnosticCheck, + DiagnosticCheckParameters, Result) class Daemon(app.LeaderComponent): """Component to manage a background daemon or any systemd unit.""" - def __init__(self, component_id, unit, strict_check=False, - listen_ports=None, alias=None): + def __init__(self, component_id: str, unit: str, + strict_check: bool = False, + listen_ports: list[tuple[int, str]] | None = None, + alias: str | None = None): """Initialize a new daemon component. 'component_id' must be a unique string across all apps and components @@ -82,7 +86,7 @@ class Daemon(app.LeaderComponent): """Return whether the daemon/unit is running.""" return action_utils.service_is_running(self.unit) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Check if the daemon is running and listening on expected ports. See :py:meth:`plinth.app.Component.diagnose`. @@ -95,15 +99,15 @@ class Daemon(app.LeaderComponent): return results - def _diagnose_unit_is_running(self): + def _diagnose_unit_is_running(self) -> DiagnosticCheck: """Check if a daemon is running.""" - from plinth.modules.diagnostics.check import DiagnosticCheck, Result - check_id = f'daemon-running-{self.unit}' result = Result.PASSED if self.is_running() else Result.FAILED description = gettext_noop('Service {service_name} is running') - parameters = {'service_name': self.unit} + parameters: DiagnosticCheckParameters = { + 'service_name': str(self.unit) + } return DiagnosticCheck(check_id, description, result, parameters) @@ -179,7 +183,9 @@ def app_is_running(app_): return True -def diagnose_port_listening(port, kind='tcp', listen_address=None): +def diagnose_port_listening( + port: int, kind: str = 'tcp', + listen_address: str | None = None) -> DiagnosticCheck: """Run a diagnostic on whether a port is being listened on. Kind must be one of inet, inet4, inet6, tcp, tcp4, tcp6, udp, @@ -187,11 +193,9 @@ def diagnose_port_listening(port, kind='tcp', listen_address=None): information. """ - from plinth.modules.diagnostics.check import DiagnosticCheck, Result - result = _check_port(port, kind, listen_address) - parameters = {'kind': kind, 'port': port} + parameters: DiagnosticCheckParameters = {'kind': kind, 'port': port} if listen_address: parameters['listen_address'] = listen_address check_id = f'daemon-listening-address-{kind}-{port}-{listen_address}' @@ -206,7 +210,8 @@ def diagnose_port_listening(port, kind='tcp', listen_address=None): parameters) -def _check_port(port, kind='tcp', listen_address=None): +def _check_port(port: int, kind: str = 'tcp', + listen_address: str | None = None) -> bool: """Return whether a port is being listened on.""" run_kind = kind @@ -228,11 +233,12 @@ def _check_port(port, kind='tcp', listen_address=None): continue # Port should match - if connection.laddr[1] != port: + if connection.laddr[1] != port: # type: ignore[misc] continue # Listen address if requested should match - if listen_address and connection.laddr[0] != listen_address: + if listen_address and connection.laddr[ + 0] != listen_address: # type: ignore[misc] continue # Special additional checks only for IPv4 @@ -244,22 +250,21 @@ def _check_port(port, kind='tcp', listen_address=None): return True # Full IPv6 address range includes mapped IPv4 address also - if connection.laddr[0] == '::': + if connection.laddr[0] == '::': # type: ignore[misc] return True return False -def diagnose_netcat(host, port, input='', negate=False): +def diagnose_netcat(host: str, port: int, remote_input: str = '', + negate: bool = False) -> DiagnosticCheck: """Run a diagnostic using netcat.""" - from plinth.modules.diagnostics.check import DiagnosticCheck, Result - try: process = subprocess.Popen(['nc', host, str(port)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - process.communicate(input=input.encode()) + process.communicate(input=remote_input.encode()) if process.returncode != 0: result = Result.FAILED if not negate else Result.PASSED else: @@ -269,10 +274,13 @@ def diagnose_netcat(host, port, input='', negate=False): check_id = f'daemon-netcat-{host}-{port}' description = gettext_noop('Connect to {host}:{port}') - parameters = {'host': host, 'port': port, 'negate': negate} + parameters: DiagnosticCheckParameters = { + 'host': host, + 'port': port, + 'negate': negate + } if negate: check_id = f'daemon-netcat-negate-{host}-{port}' description = gettext_noop('Cannot connect to {host}:{port}') - return DiagnosticCheck(check_id, description.format(host=host, port=port), - result, parameters) + return DiagnosticCheck(check_id, description, result, parameters) diff --git a/plinth/modules/diagnostics/check.py b/plinth/diagnostic_check.py similarity index 91% rename from plinth/modules/diagnostics/check.py rename to plinth/diagnostic_check.py index 70afc75fb..f67661421 100644 --- a/plinth/modules/diagnostics/check.py +++ b/plinth/diagnostic_check.py @@ -5,11 +5,14 @@ import dataclasses import json from dataclasses import dataclass, field from enum import StrEnum +from typing import TypeAlias from django.utils.translation import gettext from plinth.utils import SafeFormatter +DiagnosticCheckParameters: TypeAlias = dict[str, str | int | bool | None] + class Result(StrEnum): """The result of a diagnostic check.""" @@ -26,7 +29,7 @@ class DiagnosticCheck: check_id: str description: str result: Result = Result.NOT_DONE - parameters: dict = field(default_factory=dict) + parameters: DiagnosticCheckParameters = field(default_factory=dict) @property def translated_description(self): diff --git a/plinth/modules/apache/components.py b/plinth/modules/apache/components.py index 4fdce303e..2a9ed9e1d 100644 --- a/plinth/modules/apache/components.py +++ b/plinth/modules/apache/components.py @@ -7,7 +7,8 @@ import subprocess from django.utils.translation import gettext_noop from plinth import action_utils, app -from plinth.modules.diagnostics.check import DiagnosticCheck, Result +from plinth.diagnostic_check import (DiagnosticCheck, + DiagnosticCheckParameters, Result) from plinth.privileged import service as service_privileged from . import privileged @@ -58,7 +59,7 @@ class Webserver(app.LeaderComponent): """Disable the Apache configuration.""" privileged.disable(self.web_name, self.kind) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Check if the web path is accessible by clients. See :py:meth:`plinth.app.Component.diagnose`. @@ -135,8 +136,12 @@ class Uwsgi(app.LeaderComponent): and action_utils.service_is_running('uwsgi') -def diagnose_url(url, kind=None, env=None, check_certificate=True, - extra_options=None, wrapper=None, expected_output=None): +def diagnose_url(url: str, kind: str | None = None, + env: dict[str, str] | None = None, + check_certificate: bool = True, + extra_options: list[str] | None = None, + wrapper: str | None = None, + expected_output: str | None = None) -> DiagnosticCheck: """Run a diagnostic on whether a URL is accessible. Kind can be '4' for IPv4 or '6' for IPv6. @@ -148,7 +153,7 @@ def diagnose_url(url, kind=None, env=None, check_certificate=True, except FileNotFoundError: result = Result.ERROR - parameters = {'url': url, 'kind': kind} + parameters: DiagnosticCheckParameters = {'url': url, 'kind': kind} if kind: check_id = f'apache-url-kind-{url}-{kind}' description = gettext_noop('Access URL {url} on tcp{kind}') @@ -159,7 +164,8 @@ def diagnose_url(url, kind=None, env=None, check_certificate=True, return DiagnosticCheck(check_id, description, result, parameters) -def diagnose_url_on_all(url, expect_redirects=False, **kwargs): +def diagnose_url_on_all(url: str, expect_redirects: bool = False, + **kwargs) -> list[DiagnosticCheck]: """Run a diagnostic on whether a URL is accessible.""" results = [] for address in action_utils.get_addresses(): @@ -173,8 +179,12 @@ def diagnose_url_on_all(url, expect_redirects=False, **kwargs): return results -def check_url(url, kind=None, env=None, check_certificate=True, - extra_options=None, wrapper=None, expected_output=None): +def check_url(url: str, kind: str | None = None, + env: dict[str, str] | None = None, + check_certificate: bool = True, + extra_options: list[str] | None = None, + wrapper: str | None = None, + expected_output: str | None = None) -> bool: """Check whether a URL is accessible.""" command = ['curl', '--location', '-f', '-w', '%{response_code}'] diff --git a/plinth/modules/apache/tests/test_components.py b/plinth/modules/apache/tests/test_components.py index 6cbd1c574..39d6e1229 100644 --- a/plinth/modules/apache/tests/test_components.py +++ b/plinth/modules/apache/tests/test_components.py @@ -9,10 +9,10 @@ from unittest.mock import call, patch import pytest from plinth import app +from plinth.diagnostic_check import DiagnosticCheck, Result from plinth.modules.apache.components import (Uwsgi, Webserver, check_url, diagnose_url, diagnose_url_on_all) -from plinth.modules.diagnostics.check import DiagnosticCheck, Result def test_webserver_init(): diff --git a/plinth/modules/datetime/__init__.py b/plinth/modules/datetime/__init__.py index 743385c70..052349009 100644 --- a/plinth/modules/datetime/__init__.py +++ b/plinth/modules/datetime/__init__.py @@ -11,8 +11,8 @@ from django.utils.translation import gettext_noop from plinth import app as app_module from plinth import menu from plinth.daemon import Daemon, RelatedDaemon +from plinth.diagnostic_check import DiagnosticCheck, Result from plinth.modules.backups.components import BackupRestore -from plinth.modules.diagnostics.check import DiagnosticCheck, Result from plinth.package import Packages from . import manifest @@ -89,7 +89,7 @@ class DateTimeApp(app_module.App): **manifest.backup) self.add(backup_restore) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() if self._is_time_managed(): @@ -107,7 +107,7 @@ class DateTimeApp(app_module.App): self.enable() -def _diagnose_time_synchronized(): +def _diagnose_time_synchronized() -> DiagnosticCheck: """Check whether time is synchronized to NTP server.""" result = Result.FAILED try: diff --git a/plinth/modules/diagnostics/__init__.py b/plinth/modules/diagnostics/__init__.py index 64992bf05..9e9a56bc0 100644 --- a/plinth/modules/diagnostics/__init__.py +++ b/plinth/modules/diagnostics/__init__.py @@ -17,11 +17,12 @@ from django.utils.translation import gettext_noop from plinth import app as app_module from plinth import daemon, glib, kvstore, menu from plinth import operation as operation_module +from plinth.diagnostic_check import (CheckJSONDecoder, CheckJSONEncoder, + DiagnosticCheck, Result) from plinth.modules.apache.components import diagnose_url_on_all from plinth.modules.backups.components import BackupRestore from . import manifest -from .check import CheckJSONDecoder, CheckJSONEncoder, Result _description = [ _('The system diagnostic test will run a number of checks on your ' @@ -75,7 +76,7 @@ class DiagnosticsApp(app_module.App): super().setup(old_version) self.enable() - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() results.append(daemon.diagnose_port_listening(8000, 'tcp4')) diff --git a/plinth/modules/diagnostics/views.py b/plinth/modules/diagnostics/views.py index 6a9437631..6102db56e 100644 --- a/plinth/modules/diagnostics/views.py +++ b/plinth/modules/diagnostics/views.py @@ -14,10 +14,10 @@ from django.views.generic import TemplateView from plinth import operation from plinth.app import App +from plinth.diagnostic_check import Result from plinth.modules import diagnostics from plinth.views import AppView -from .check import Result from .forms import ConfigureForm logger = logging.getLogger(__name__) diff --git a/plinth/modules/firewall/__init__.py b/plinth/modules/firewall/__init__.py index 9de569029..2eb1c87ac 100644 --- a/plinth/modules/firewall/__init__.py +++ b/plinth/modules/firewall/__init__.py @@ -10,8 +10,8 @@ from django.utils.translation import gettext_noop from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import Daemon +from plinth.diagnostic_check import DiagnosticCheck, Result from plinth.modules.backups.components import BackupRestore -from plinth.modules.diagnostics.check import DiagnosticCheck, Result from plinth.package import Packages, install from plinth.utils import Version, format_lazy, import_from_gi @@ -96,7 +96,7 @@ class FirewallApp(app_module.App): _run_setup() return True - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() config = privileged.get_config() @@ -265,7 +265,8 @@ def remove_passthrough(ipv, *args): config_direct.removePassthrough('(sas)', ipv, args) -def _diagnose_default_zone(config): +def _diagnose_default_zone( + config: privileged.FirewallConfig) -> DiagnosticCheck: """Diagnose whether the default zone is external.""" check_id = 'firewall-default-zone' description = gettext_noop('Default zone is external') @@ -274,7 +275,8 @@ def _diagnose_default_zone(config): return DiagnosticCheck(check_id, description, result) -def _diagnose_firewall_backend(config): +def _diagnose_firewall_backend( + config: privileged.FirewallConfig) -> DiagnosticCheck: """Diagnose whether the firewall backend is nftables.""" check_id = 'firewall-backend' description = gettext_noop('Firewall backend is nftables') @@ -283,7 +285,8 @@ def _diagnose_firewall_backend(config): return DiagnosticCheck(check_id, description, result) -def _diagnose_direct_passthroughs(config): +def _diagnose_direct_passthroughs( + config: privileged.FirewallConfig) -> DiagnosticCheck: """Diagnose direct passthroughs for local service protection. Currently, we just check that the number of passthroughs is at least 12, diff --git a/plinth/modules/firewall/components.py b/plinth/modules/firewall/components.py index 666292c18..e3c381b26 100644 --- a/plinth/modules/firewall/components.py +++ b/plinth/modules/firewall/components.py @@ -5,16 +5,19 @@ App component for other apps to use firewall functionality. import logging import re -from typing import ClassVar +from typing import ClassVar, TypeAlias from django.utils.translation import gettext_noop from plinth import app +from plinth.diagnostic_check import (DiagnosticCheck, + DiagnosticCheckParameters, Result) from plinth.modules import firewall -from plinth.modules.diagnostics.check import DiagnosticCheck, Result logger = logging.getLogger(__name__) +_list_type: TypeAlias = list + class Firewall(app.FollowerComponent): """Component to open/close firewall ports for an app.""" @@ -114,7 +117,7 @@ class Firewall(app.FollowerComponent): if not re.fullmatch(r'tun\d+', interface) ] - def diagnose(self): + def diagnose(self) -> _list_type[DiagnosticCheck]: """Check if the firewall ports are open and only as expected. See :py:meth:`plinth.app.Component.diagnose`. @@ -124,7 +127,7 @@ class Firewall(app.FollowerComponent): internal_ports = firewall.get_enabled_services(zone='internal') external_ports = firewall.get_enabled_services(zone='external') for port_detail in self.ports_details: - port = port_detail['name'] + port = str(port_detail['name']) details = ', '.join( (f'{port_number}/{protocol}' for port_number, protocol in port_detail['details'])) @@ -134,7 +137,10 @@ class Firewall(app.FollowerComponent): result = Result.PASSED if port in internal_ports else Result.FAILED description = gettext_noop( 'Port {name} ({details}) available for internal networks') - parameters = {'name': port, 'details': details} + parameters: DiagnosticCheckParameters = { + 'name': port, + 'details': details + } results.append( DiagnosticCheck(check_id, description, result, parameters)) diff --git a/plinth/modules/firewall/privileged.py b/plinth/modules/firewall/privileged.py index f673b50dc..4463b528e 100644 --- a/plinth/modules/firewall/privileged.py +++ b/plinth/modules/firewall/privileged.py @@ -2,12 +2,15 @@ """Configuration helper for FreedomBox firewall interface.""" import subprocess +from typing import TypeAlias import augeas from plinth import action_utils from plinth.actions import privileged +FirewallConfig: TypeAlias = dict[str, str | list[str]] + def _flush_iptables_rules(): """Flush firewalld iptables rules before restarting it. @@ -132,9 +135,9 @@ def setup(): @privileged -def get_config(): +def get_config() -> FirewallConfig: """Return firewalld configuration for diagnostics.""" - config = {} + config: FirewallConfig = {} # Get the default zone. output = subprocess.check_output(['firewall-cmd', '--get-default-zone']) diff --git a/plinth/modules/firewall/tests/test_components.py b/plinth/modules/firewall/tests/test_components.py index e4a53f303..a6d943db9 100644 --- a/plinth/modules/firewall/tests/test_components.py +++ b/plinth/modules/firewall/tests/test_components.py @@ -8,7 +8,7 @@ from unittest.mock import call, patch import pytest from plinth.app import App -from plinth.modules.diagnostics.check import DiagnosticCheck, Result +from plinth.diagnostic_check import DiagnosticCheck, Result from plinth.modules.firewall.components import (Firewall, FirewallLocalProtection) diff --git a/plinth/modules/letsencrypt/__init__.py b/plinth/modules/letsencrypt/__init__.py index ab42b18f6..823bd4045 100644 --- a/plinth/modules/letsencrypt/__init__.py +++ b/plinth/modules/letsencrypt/__init__.py @@ -11,10 +11,10 @@ from django.utils.translation import gettext_noop from plinth import app as app_module from plinth import cfg, menu from plinth.config import DropinConfigs +from plinth.diagnostic_check import DiagnosticCheck, Result from plinth.modules import names from plinth.modules.apache.components import diagnose_url from plinth.modules.backups.components import BackupRestore -from plinth.modules.diagnostics.check import DiagnosticCheck, Result from plinth.modules.names.components import DomainType from plinth.package import Packages from plinth.signals import domain_added, domain_removed, post_app_loading @@ -89,7 +89,7 @@ class LetsEncryptApp(app_module.App): post_app_loading.connect(_certificate_handle_modified) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() diff --git a/plinth/modules/networks/__init__.py b/plinth/modules/networks/__init__.py index e793dddb0..df9e168d2 100644 --- a/plinth/modules/networks/__init__.py +++ b/plinth/modules/networks/__init__.py @@ -9,6 +9,7 @@ from django.utils.translation import gettext_lazy as _ from plinth import app as app_module from plinth import daemon, kvstore, menu, network from plinth.config import DropinConfigs +from plinth.diagnostic_check import DiagnosticCheck from plinth.package import Packages from . import privileged @@ -72,7 +73,7 @@ class NetworksApp(app_module.App): ]) self.add(dropin_configs) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() diff --git a/plinth/modules/privoxy/__init__.py b/plinth/modules/privoxy/__init__.py index 72f83ea22..0e4a01e28 100644 --- a/plinth/modules/privoxy/__init__.py +++ b/plinth/modules/privoxy/__init__.py @@ -11,6 +11,7 @@ from plinth import action_utils from plinth import app as app_module from plinth import cfg, frontpage, menu from plinth.daemon import Daemon +from plinth.diagnostic_check import DiagnosticCheck from plinth.modules.apache.components import diagnose_url from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall @@ -86,7 +87,7 @@ class PrivoxyApp(app_module.App): **manifest.backup) self.add(backup_restore) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() results.append(diagnose_url('https://www.debian.org')) @@ -102,16 +103,16 @@ class PrivoxyApp(app_module.App): self.enable() -def diagnose_url_with_proxy(): +def diagnose_url_with_proxy() -> list[DiagnosticCheck]: """Run a diagnostic on a URL with a proxy.""" url = 'https://debian.org/' # Gives a simple redirect to www. results = [] for address in action_utils.get_addresses(): - proxy = 'http://{host}:8118/'.format(host=address['url_address']) + proxy = f'http://{address["url_address"]}:8118/' env = {'https_proxy': proxy} - result = diagnose_url(url, kind=address['kind'], env=env) + result = diagnose_url(url, kind=str(address['kind']), env=env) result.check_id = f'privoxy-url-proxy-kind-{url}-{address["kind"]}' result.description = gettext_noop( 'Access {url} with proxy {proxy} on tcp{kind}') diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py index d72781b7b..d603aab2b 100644 --- a/plinth/modules/tor/__init__.py +++ b/plinth/modules/tor/__init__.py @@ -13,10 +13,10 @@ from plinth import cfg, kvstore, menu from plinth import setup as setup_module_ # Not setup_module, for pytest from plinth.daemon import (Daemon, app_is_running, diagnose_netcat, diagnose_port_listening) +from plinth.diagnostic_check import DiagnosticCheck, Result from plinth.modules import torproxy from plinth.modules.apache.components import Webserver from plinth.modules.backups.components import BackupRestore -from plinth.modules.diagnostics.check import DiagnosticCheck, Result from plinth.modules.firewall.components import Firewall from plinth.modules.names.components import DomainType from plinth.modules.torproxy.utils import is_apt_transport_tor_enabled @@ -123,7 +123,7 @@ class TorApp(app_module.App): super().disable() update_hidden_service_domain() - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() @@ -235,7 +235,7 @@ def update_hidden_service_domain(status=None): name=status['hs_hostname'], services=services) -def _diagnose_control_port(): +def _diagnose_control_port() -> list[DiagnosticCheck]: """Diagnose whether Tor control port is open on 127.0.0.1 only.""" results = [] @@ -249,7 +249,7 @@ def _diagnose_control_port(): negate = False results.append( - diagnose_netcat(address['address'], 9051, input='QUIT\n', - negate=negate)) + diagnose_netcat(str(address['address']), 9051, + remote_input='QUIT\n', negate=negate)) return results diff --git a/plinth/modules/torproxy/__init__.py b/plinth/modules/torproxy/__init__.py index 289be5fb6..cd38b8c17 100644 --- a/plinth/modules/torproxy/__init__.py +++ b/plinth/modules/torproxy/__init__.py @@ -11,6 +11,7 @@ from django.utils.translation import gettext_noop from plinth import app as app_module from plinth import cfg, frontpage, kvstore, menu from plinth.daemon import Daemon +from plinth.diagnostic_check import DiagnosticCheck from plinth.modules.apache.components import diagnose_url from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall @@ -100,7 +101,7 @@ class TorProxyApp(app_module.App): privileged.configure(apt_transport_tor=False) super().disable() - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() results.append(_diagnose_url_via_tor('http://www.debian.org', '4')) @@ -133,7 +134,8 @@ class TorProxyApp(app_module.App): privileged.uninstall() -def _diagnose_url_via_tor(url, kind=None): +def _diagnose_url_via_tor(url: str, + kind: str | None = None) -> DiagnosticCheck: """Diagnose whether a URL is reachable via Tor.""" result = diagnose_url(url, kind=kind, wrapper='torsocks') result.check_id = 'torproxy-url' @@ -142,7 +144,7 @@ def _diagnose_url_via_tor(url, kind=None): return result -def _diagnose_tor_use(url, kind=None): +def _diagnose_tor_use(url: str, kind: str | None = None) -> DiagnosticCheck: """Diagnose whether webpage at URL reports that we are using Tor.""" expected_output = 'Congratulations. This browser is configured to use Tor.' result = diagnose_url(url, kind=kind, wrapper='torsocks', diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py index c9774b405..61b398c6a 100644 --- a/plinth/modules/users/__init__.py +++ b/plinth/modules/users/__init__.py @@ -13,7 +13,8 @@ from plinth import app as app_module from plinth import cfg, menu from plinth.config import DropinConfigs from plinth.daemon import Daemon -from plinth.modules.diagnostics.check import DiagnosticCheck, Result +from plinth.diagnostic_check import (DiagnosticCheck, + DiagnosticCheckParameters, Result) from plinth.package import Packages from plinth.privileged import service as service_privileged @@ -85,7 +86,7 @@ class UsersApp(app_module.App): groups=groups) self.add(users_and_groups) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" results = super().diagnose() @@ -112,7 +113,7 @@ class UsersApp(app_module.App): privileged.create_group('freedombox-share') -def _diagnose_ldap_entry(search_item): +def _diagnose_ldap_entry(search_item: str) -> DiagnosticCheck: """Diagnose that an LDAP entry exists.""" check_id = f'users-ldap-entry-{search_item}' result = Result.FAILED @@ -125,12 +126,13 @@ def _diagnose_ldap_entry(search_item): pass description = gettext_noop('Check LDAP entry "{search_item}"') - parameters = {'search_item': search_item} + parameters: DiagnosticCheckParameters = {'search_item': search_item} return DiagnosticCheck(check_id, description, result, parameters) -def _diagnose_nslcd_config(config, key, value): +def _diagnose_nslcd_config(config: dict[str, str], key: str, + value: str) -> DiagnosticCheck: """Diagnose that nslcd has a configuration.""" check_id = f'users-nslcd-config-{key}' try: @@ -139,12 +141,12 @@ def _diagnose_nslcd_config(config, key, value): result = Result.FAILED description = gettext_noop('Check nslcd config "{key} {value}"') - parameters = {'key': key, 'value': value} + parameters: DiagnosticCheckParameters = {'key': key, 'value': value} return DiagnosticCheck(check_id, description, result, parameters) -def _diagnose_nsswitch_config(): +def _diagnose_nsswitch_config() -> list[DiagnosticCheck]: """Diagnose that Name Service Switch is configured to use LDAP.""" nsswitch_conf = '/etc/nsswitch.conf' aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + @@ -169,7 +171,7 @@ def _diagnose_nsswitch_config(): break description = gettext_noop('Check nsswitch config "{database}"') - parameters = {'database': database} + parameters: DiagnosticCheckParameters = {'database': database} results.append( DiagnosticCheck(check_id, description, result, parameters)) diff --git a/plinth/modules/users/privileged.py b/plinth/modules/users/privileged.py index a67284e84..b1189691b 100644 --- a/plinth/modules/users/privileged.py +++ b/plinth/modules/users/privileged.py @@ -178,7 +178,7 @@ def _configure_ldapscripts(): @privileged -def get_nslcd_config(): +def get_nslcd_config() -> dict[str, str]: """Get nslcd configuration for diagnostics.""" nslcd_conf = '/etc/nslcd.conf' aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD + diff --git a/plinth/package.py b/plinth/package.py index 5de556c60..94ff19ee8 100644 --- a/plinth/package.py +++ b/plinth/package.py @@ -12,6 +12,8 @@ from django.utils.translation import gettext_lazy, gettext_noop import plinth.privileged.packages as privileged from plinth import app as app_module +from plinth.diagnostic_check import (DiagnosticCheck, + DiagnosticCheckParameters, Result) from plinth.errors import MissingPackageError from plinth.utils import format_lazy @@ -200,10 +202,8 @@ class Packages(app_module.FollowerComponent): uninstall([package for package in packages if package in packages_set], purge=True) - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return results.""" - from plinth.modules.diagnostics.check import DiagnosticCheck, Result - results = super().diagnose() cache = apt.Cache() for package_expression in self.package_expressions: @@ -213,7 +213,9 @@ class Packages(app_module.FollowerComponent): check_id = f'package-available-{package_expression}' description = gettext_noop('Package {package_expression} is ' 'not available for install') - parameters = {'package_expression': str(package_expression)} + parameters: DiagnosticCheckParameters = { + 'package_expression': str(package_expression) + } results.append( DiagnosticCheck(check_id, description, Result.FAILED, parameters)) @@ -223,16 +225,17 @@ class Packages(app_module.FollowerComponent): latest_version = '?' if package_name in cache: package = cache[package_name] - latest_version = package.candidate.version - if package.candidate.is_installed: - result = Result.PASSED + if package.candidate: + latest_version = package.candidate.version + if package.candidate.is_installed: + result = Result.PASSED check_id = f'package-latest-{package_name}' description = gettext_noop('Package {package_name} is the latest ' 'version ({latest_version})') parameters = { - 'package_name': package_name, - 'latest_version': latest_version, + 'package_name': str(package_name), + 'latest_version': str(latest_version) } results.append( DiagnosticCheck(check_id, description, result, parameters)) diff --git a/plinth/tests/test_app.py b/plinth/tests/test_app.py index bb161ba9f..86bcfec65 100644 --- a/plinth/tests/test_app.py +++ b/plinth/tests/test_app.py @@ -10,7 +10,7 @@ import pytest from plinth.app import (App, Component, EnableState, FollowerComponent, Info, LeaderComponent, apps_init) -from plinth.modules.diagnostics.check import DiagnosticCheck, Result +from plinth.diagnostic_check import DiagnosticCheck, Result # pylint: disable=protected-access @@ -34,7 +34,7 @@ class LeaderTest(FollowerComponent): """Test class for using LeaderComponent in tests.""" is_leader = True - def diagnose(self): + def diagnose(self) -> list[DiagnosticCheck]: """Return diagnostic results.""" return [ DiagnosticCheck('test-result-' + self.component_id, diff --git a/plinth/tests/test_config.py b/plinth/tests/test_config.py index 08376d358..6f82b8172 100644 --- a/plinth/tests/test_config.py +++ b/plinth/tests/test_config.py @@ -9,7 +9,7 @@ import pytest from plinth.app import App from plinth.config import DropinConfigs -from plinth.modules.diagnostics.check import DiagnosticCheck, Result +from plinth.diagnostic_check import DiagnosticCheck, Result pytestmark = pytest.mark.usefixtures('mock_privileged') privileged_modules_to_mock = ['plinth.privileged.config'] diff --git a/plinth/tests/test_daemon.py b/plinth/tests/test_daemon.py index 9dabdf092..d6cfcff69 100644 --- a/plinth/tests/test_daemon.py +++ b/plinth/tests/test_daemon.py @@ -12,7 +12,7 @@ import pytest from plinth.app import App, FollowerComponent, Info from plinth.daemon import (Daemon, RelatedDaemon, SharedDaemon, app_is_running, diagnose_netcat, diagnose_port_listening) -from plinth.modules.diagnostics.check import DiagnosticCheck, Result +from plinth.diagnostic_check import DiagnosticCheck, Result privileged_modules_to_mock = ['plinth.privileged.service'] @@ -295,32 +295,32 @@ def test_diagnose_port_listening(connections): def test_diagnose_netcat(popen): """Test running diagnostic test using netcat.""" popen().returncode = 0 - result = diagnose_netcat('test-host', 3300, input='test-input') + result = diagnose_netcat('test-host', 3300, remote_input='test-input') parameters = {'host': 'test-host', 'port': 3300, 'negate': False} assert result == DiagnosticCheck('daemon-netcat-test-host-3300', - 'Connect to test-host:3300', - Result.PASSED, parameters) + 'Connect to {host}:{port}', Result.PASSED, + parameters) assert popen.mock_calls[1][1] == (['nc', 'test-host', '3300'], ) assert popen.mock_calls[2] == call().communicate(input=b'test-input') - result = diagnose_netcat('test-host', 3300, input='test-input', + result = diagnose_netcat('test-host', 3300, remote_input='test-input', negate=True) parameters2 = parameters.copy() parameters2['negate'] = True assert result == DiagnosticCheck('daemon-netcat-negate-test-host-3300', - 'Cannot connect to test-host:3300', + 'Cannot connect to {host}:{port}', Result.FAILED, parameters2) popen().returncode = 1 - result = diagnose_netcat('test-host', 3300, input='test-input') + result = diagnose_netcat('test-host', 3300, remote_input='test-input') assert result == DiagnosticCheck('daemon-netcat-test-host-3300', - 'Connect to test-host:3300', - Result.FAILED, parameters) + 'Connect to {host}:{port}', Result.FAILED, + parameters) - result = diagnose_netcat('test-host', 3300, input='test-input', + result = diagnose_netcat('test-host', 3300, remote_input='test-input', negate=True) assert result == DiagnosticCheck('daemon-netcat-negate-test-host-3300', - 'Cannot connect to test-host:3300', + 'Cannot connect to {host}:{port}', Result.PASSED, parameters2) diff --git a/plinth/modules/diagnostics/tests/test_check.py b/plinth/tests/test_diagnostic_check.py similarity index 91% rename from plinth/modules/diagnostics/tests/test_check.py rename to plinth/tests/test_diagnostic_check.py index 734200ca8..caf6f1199 100644 --- a/plinth/modules/diagnostics/tests/test_check.py +++ b/plinth/tests/test_diagnostic_check.py @@ -5,9 +5,8 @@ import json import pytest -from plinth.modules.diagnostics.check import (CheckJSONDecoder, - CheckJSONEncoder, - DiagnosticCheck, Result) +from plinth.diagnostic_check import (CheckJSONDecoder, CheckJSONEncoder, + DiagnosticCheck, Result) def test_result(): diff --git a/plinth/tests/test_package.py b/plinth/tests/test_package.py index 76ec16f44..993484d08 100644 --- a/plinth/tests/test_package.py +++ b/plinth/tests/test_package.py @@ -9,8 +9,8 @@ from unittest.mock import Mock, call, patch import pytest from plinth.app import App +from plinth.diagnostic_check import DiagnosticCheck, Result from plinth.errors import MissingPackageError -from plinth.modules.diagnostics.check import DiagnosticCheck, Result from plinth.package import Package, Packages, packages_installed From 22671510e63fac0d2925aabad76d3bf1b01b29bb Mon Sep 17 00:00:00 2001 From: Veiko Aasa Date: Sat, 9 Mar 2024 13:58:22 +0200 Subject: [PATCH 13/63] samba: Ignore non-existent users who are in freedombox-share group Fixes error 500 when trying to open Samba app page when at least one of the users in freedombox-share group doesn't exist. Tests performed in both stable and testing containers: - Installed Samba app. - Installed Deluge app (Plinth install/setup fails but the Debian package itself was installed). - Did `apt remove --purge deluged` from command line. - Checked that the debian-deluged user doesn't exist (`getent passwd`) and the user is in the freedombox-share group (`getent group`). - Checked that the Samba app page opens without errors. - Checked that all the Samba tests pass. Fixes #2411. Signed-off-by: Veiko Aasa Reviewed-by: Sunil Mohan Adapa --- plinth/modules/samba/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plinth/modules/samba/__init__.py b/plinth/modules/samba/__init__.py index 345e3ce6b..f81cd5d88 100644 --- a/plinth/modules/samba/__init__.py +++ b/plinth/modules/samba/__init__.py @@ -137,7 +137,11 @@ def get_users(): allowed_users = [] for group_user in group_users: - uid = pwd.getpwnam(group_user).pw_uid + try: + uid = pwd.getpwnam(group_user).pw_uid + except KeyError: # User doesn't exist + continue + if uid > 1000: allowed_users.append(group_user) From a488ee4d435509d055eec2f360f885d6b271637a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 17:54:42 -0800 Subject: [PATCH 14/63] action_utils: Implement method for starting a service temporarily Used when a service is needed for an operation but we don't wish to keep it running after the operation. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/action_utils.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plinth/action_utils.py b/plinth/action_utils.py index 3e6bffaca..4bf5a1a1b 100644 --- a/plinth/action_utils.py +++ b/plinth/action_utils.py @@ -48,6 +48,20 @@ def service_is_running(servicename): return False +@contextmanager +def service_ensure_running(service_name): + """Ensure a service is running and return to previous state.""" + starting_state = service_is_running(service_name) + if not starting_state: + service_enable(service_name) + + try: + yield starting_state + finally: + if not starting_state: + service_disable(service_name) + + def service_is_enabled(service_name, strict_check=False): """Check if service is enabled in systemd. From d79ba1cede89e1e1c686915f67f5c70b39c0169a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 17:56:11 -0800 Subject: [PATCH 15/63] zoph: Don't fail setup if mysql installed but not running Tests: - Install wordpress and disable it. This will install mysql and disable it. Then install zoph installation should succeed. - Disable zoph and re-run setup. Setup should succeed. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/zoph/privileged.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/plinth/modules/zoph/privileged.py b/plinth/modules/zoph/privileged.py index e5f3b79b9..67e386a48 100644 --- a/plinth/modules/zoph/privileged.py +++ b/plinth/modules/zoph/privileged.py @@ -42,16 +42,20 @@ def _zoph_configure(key, value): @privileged def setup(): - """Setup Zoph configuration.""" - _zoph_configure('import.enable', 'true') - _zoph_configure('import.upload', 'true') - _zoph_configure('import.rotate', 'true') - _zoph_configure('path.unzip', 'unzip') - _zoph_configure('path.untar', 'tar xvf') - _zoph_configure('path.ungz', 'gunzip') + """Setup Zoph configuration. - # Maps using OpenStreetMap is enabled by default. - _zoph_configure('maps.provider', 'osm') + May be called when app is disabled. + """ + with action_utils.service_ensure_running('mysql'): + _zoph_configure('import.enable', 'true') + _zoph_configure('import.upload', 'true') + _zoph_configure('import.rotate', 'true') + _zoph_configure('path.unzip', 'unzip') + _zoph_configure('path.untar', 'tar xvf') + _zoph_configure('path.ungz', 'gunzip') + + # Maps using OpenStreetMap is enabled by default. + _zoph_configure('maps.provider', 'osm') def _get_db_name(): From 717e8cd7f572a7a2324e56db7064107012b9cb8d Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 17:57:30 -0800 Subject: [PATCH 16/63] wordpress: Don't fail setup if mysql installed but not running Tests: - Install zoph and disable it. This will install mysql and disable it. Then install wordpress. Installation should succeed. - Disable wordpress and re-run setup. Setup should succeed. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/wordpress/privileged.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plinth/modules/wordpress/privileged.py b/plinth/modules/wordpress/privileged.py index 73a74adbe..dcb191562 100644 --- a/plinth/modules/wordpress/privileged.py +++ b/plinth/modules/wordpress/privileged.py @@ -36,8 +36,9 @@ def setup(): db_password = _generate_secret_key(16) _create_config_file(DB_HOST, DB_NAME, DB_USER, db_password) - _create_database(DB_NAME) - _set_privileges(DB_HOST, DB_NAME, DB_USER, db_password) + with action_utils.service_ensure_running('mysql'): + _create_database(DB_NAME) + _set_privileges(DB_HOST, DB_NAME, DB_USER, db_password) def _create_config_file(db_host, db_name, db_user, db_password): From 524fdf60492ae6c3045d5694795cb4dfee6784e1 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 17:58:41 -0800 Subject: [PATCH 17/63] app: Add ability to hide configuration form when app is disabled - Some apps store their configuration in database. The database server may not be running when app is disabled. Configuration changes may then not be possible for such apps. Provide the ability to disable configuration for apps that don't support configuration changes when disabled. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/app.py | 6 ++++++ plinth/tests/test_app.py | 3 +++ plinth/views.py | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/plinth/app.py b/plinth/app.py index 6969720f1..c093ceb32 100644 --- a/plinth/app.py +++ b/plinth/app.py @@ -42,6 +42,10 @@ class App: the app. This flag is currently set during backup and restore operations but UI changes are currently not implemented. + 'configure_when_disabled' is a boolean indicating whether the app can + configured while it is disabled. Some apps such those whose configuration + is stored in a database can't be configured while they are disabled because + the database server may not be running when the app is disabled. """ app_id: str | None = None @@ -51,6 +55,8 @@ class App: locked: bool = False # Whether user interaction with the app is allowed. # XXX: Lockdown the application UI by implementing a middleware + configure_when_disabled: bool = True + _all_apps: ClassVar[collections.OrderedDict[ str, 'App']] = collections.OrderedDict() diff --git a/plinth/tests/test_app.py b/plinth/tests/test_app.py index 86bcfec65..1ea6fc523 100644 --- a/plinth/tests/test_app.py +++ b/plinth/tests/test_app.py @@ -67,6 +67,9 @@ def test_app_instantiation(): assert app.app_id == 'test-app' assert app._all_apps['test-app'] == app assert len(app._all_apps) == 1 + assert app.can_be_disabled + assert not app.locked + assert app.configure_when_disabled def test_app_get(): diff --git a/plinth/views.py b/plinth/views.py index da37eeaea..e79c3fb5e 100644 --- a/plinth/views.py +++ b/plinth/views.py @@ -215,6 +215,11 @@ class AppView(FormView): if not self.form_class: return None + if not self.app.configure_when_disabled: + status = self.get_common_status() + if not status['is_enabled']: + return None + return super().get_form(*args, **kwargs) def _get_common_status(self): From 0edb6a121929a5c01eca1637197fef2c37bf3b5f Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 18:00:21 -0800 Subject: [PATCH 18/63] zoph: Hide configuration form when app is disabled - MySQL server may be disabled when zoph is disabled. Trying to retrieve configuration or trying to set the configuration at the time will result in failures. So, disable the configuration form so that get/set of configuration does not happen. Tests: - Disable zoph. Configuration form will disappear. Re-enable zoph, configuration form will reappear. - Functional tests for zoph pass. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/zoph/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plinth/modules/zoph/__init__.py b/plinth/modules/zoph/__init__.py index b5bbd75f0..0d2c6a6a4 100644 --- a/plinth/modules/zoph/__init__.py +++ b/plinth/modules/zoph/__init__.py @@ -46,6 +46,8 @@ class ZophApp(app_module.App): _version = 2 + configure_when_disabled = False + def __init__(self) -> None: """Create components for the app.""" super().__init__() From 8f5dc14183c40f1bb51d86d4c6f435d1a6cd1f76 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 18:03:35 -0800 Subject: [PATCH 19/63] app: views: Expose method to get enabled/disabled state and cache it - So that it can be used by derived classes. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/views.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/plinth/views.py b/plinth/views.py index e79c3fb5e..b8ee67323 100644 --- a/plinth/views.py +++ b/plinth/views.py @@ -222,7 +222,7 @@ class AppView(FormView): return super().get_form(*args, **kwargs) - def _get_common_status(self): + def get_common_status(self): """Return the status needed for form and template. Avoid multiple queries to expensive operations such as @@ -238,7 +238,7 @@ class AppView(FormView): def get_initial(self): """Return the status of the app to fill in the form.""" initial = super().get_initial() - initial.update(self._get_common_status()) + initial.update(self.get_common_status()) return initial def form_valid(self, form): @@ -257,9 +257,7 @@ class AppView(FormView): if not self.app.can_be_disabled: return None - initial = { - 'should_enable': not self._get_common_status()['is_enabled'] - } + initial = {'should_enable': not self.get_common_status()['is_enabled']} return forms.AppEnableDisableForm(initial=initial) def enable_disable_form_valid(self, form): @@ -276,7 +274,7 @@ class AppView(FormView): def get_context_data(self, *args, **kwargs): """Add service to the context data.""" context = super().get_context_data(*args, **kwargs) - context.update(self._get_common_status()) + context.update(self.get_common_status()) context['app_id'] = self.app.app_id context['is_running'] = app_is_running(self.app) context['app_info'] = self.app.info @@ -345,9 +343,8 @@ class SetupView(TemplateView): context['setup_state'] = setup_state context['operations'] = operation.manager.filter(app.app_id) context['show_rerun_setup'] = False - context['show_uninstall'] = ( - not app.info.is_essential - and setup_state != app_module.App.SetupState.NEEDS_SETUP) + context['show_uninstall'] = (not app.info.is_essential and setup_state + != app_module.App.SetupState.NEEDS_SETUP) # Perform expensive operation only if needed. if not context['operations']: From 6646512a0adab6943503ec47372502fb28805911 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 18:04:29 -0800 Subject: [PATCH 20/63] zoph: Don't redirect to setup page when app is disabled - When app is disabled, it can't be setup as it requires database server and connecting to the database. - If app is disabled, we don't show configuration any more, so redirection to setup page is also not needed. This results in neither setup nor configuration being shown when app is disabled. - During uninstall process, app is disable for first. So, the workaround implemented in is_configured() is no longer needed. Tests: - Install zoph. Setup page is shown. Disable the app by disabling the apache configuration for it and restart service. Setup is no longer shown. - Uninstall zoph. During the uninstall setup, when page is refreshing, setup page is not shown. Reviewed-by: James Valleroy --- plinth/modules/zoph/privileged.py | 10 +++------- plinth/modules/zoph/views.py | 10 +++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/plinth/modules/zoph/privileged.py b/plinth/modules/zoph/privileged.py index 67e386a48..fe3decdcf 100644 --- a/plinth/modules/zoph/privileged.py +++ b/plinth/modules/zoph/privileged.py @@ -95,13 +95,9 @@ def set_configuration(enable_osm: bool | None = None, @privileged def is_configured() -> bool | None: """Return whether zoph app is configured.""" - try: - process = subprocess.run( - ['zoph', '--get-config', 'interface.user.remote'], - stdout=subprocess.PIPE, check=True) - return process.stdout.decode().strip() == 'true' - except FileNotFoundError: - return None + process = subprocess.run(['zoph', '--get-config', 'interface.user.remote'], + stdout=subprocess.PIPE, check=True) + return process.stdout.decode().strip() == 'true' @privileged diff --git a/plinth/modules/zoph/views.py b/plinth/modules/zoph/views.py index f646f5de6..9e9cabb1b 100644 --- a/plinth/modules/zoph/views.py +++ b/plinth/modules/zoph/views.py @@ -48,12 +48,12 @@ class ZophAppView(views.AppView): def dispatch(self, request, *args, **kwargs): """Redirect to setup page if setup is not done yet.""" - is_configured = privileged.is_configured() - if is_configured is False: - return redirect('zoph:setup') + status = self.get_common_status() + if status['is_enabled']: + # When disabled, such as when uninstalling + if privileged.is_configured() is False: + return redirect('zoph:setup') - # During operations such as uninstall, zoph command may not be - # available, let the base class show operations view instead. return super().dispatch(request, *args, **kwargs) def get_initial(self): From 17e84419b838e38a2bdbfa0413c83568371aeb96 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 7 Mar 2024 22:26:22 -0800 Subject: [PATCH 21/63] zoph: Don't fail with backup/restore if app is disabled Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/zoph/privileged.py | 33 ++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/plinth/modules/zoph/privileged.py b/plinth/modules/zoph/privileged.py index fe3decdcf..356612bf9 100644 --- a/plinth/modules/zoph/privileged.py +++ b/plinth/modules/zoph/privileged.py @@ -102,19 +102,28 @@ def is_configured() -> bool | None: @privileged def dump_database(): - """Dump database to file.""" - db_name = _get_db_name() - os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True) - with open(DB_BACKUP_FILE, 'w', encoding='utf-8') as db_backup_file: - subprocess.run(['mysqldump', db_name], stdout=db_backup_file, - check=True) + """Dump database to file. + + May be called when app is disabled. + """ + with action_utils.service_ensure_running('mysql'): + db_name = _get_db_name() + os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True) + with open(DB_BACKUP_FILE, 'w', encoding='utf-8') as db_backup_file: + subprocess.run(['mysqldump', db_name], stdout=db_backup_file, + check=True) @privileged def restore_database(): - """Restore database from file.""" - db_name = _get_db_name() - subprocess.run(['mysqladmin', '--force', 'drop', db_name], check=False) - subprocess.run(['mysqladmin', 'create', db_name], check=True) - with open(DB_BACKUP_FILE, 'r', encoding='utf-8') as db_restore_file: - subprocess.run(['mysql', db_name], stdin=db_restore_file, check=True) + """Restore database from file. + + May be called when app is disabled. + """ + with action_utils.service_ensure_running('mysql'): + db_name = _get_db_name() + subprocess.run(['mysqladmin', '--force', 'drop', db_name], check=False) + subprocess.run(['mysqladmin', 'create', db_name], check=True) + with open(DB_BACKUP_FILE, 'r', encoding='utf-8') as db_restore_file: + subprocess.run(['mysql', db_name], stdin=db_restore_file, + check=True) From 74fc8e08da48a33559c0543ce31c2cfc0f9f2aa2 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 11:53:57 -0800 Subject: [PATCH 22/63] zoph: Uninstall fully so that reinstall works Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/zoph/__init__.py | 6 +++++ plinth/modules/zoph/privileged.py | 44 +++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/plinth/modules/zoph/__init__.py b/plinth/modules/zoph/__init__.py index 0d2c6a6a4..0197788a6 100644 --- a/plinth/modules/zoph/__init__.py +++ b/plinth/modules/zoph/__init__.py @@ -110,6 +110,12 @@ class ZophApp(app_module.App): if self.get_component('webserver-zoph').is_enabled(): self.enable() + def uninstall(self): + """De-configure and uninstall the app.""" + # Before package uninstall, so that config file is still available + privileged.uninstall() + super().uninstall() + class ZophBackupRestore(BackupRestore): """Component to backup/restore Zoph database""" diff --git a/plinth/modules/zoph/privileged.py b/plinth/modules/zoph/privileged.py index 356612bf9..0c3087cad 100644 --- a/plinth/modules/zoph/privileged.py +++ b/plinth/modules/zoph/privileged.py @@ -3,6 +3,7 @@ import configparser import os +import pathlib import re import subprocess @@ -10,6 +11,7 @@ from plinth import action_utils from plinth.actions import privileged APACHE_CONF = '/etc/apache2/conf-available/zoph.conf' +DB_CONF = pathlib.Path('/etc/zoph.ini') DB_BACKUP_FILE = '/var/lib/plinth/backups-data/zoph-database.sql' @@ -18,7 +20,9 @@ def pre_install(): """Preseed debconf values before packages are installed.""" action_utils.debconf_set_selections([ 'zoph zoph/dbconfig-install boolean true', - 'zoph zoph/mysql/admin-user string root' + 'zoph zoph/dbconfig-upgrade boolean true', + 'zoph zoph/dbconfig-remove boolean true', + 'zoph zoph/mysql/admin-user string root', ]) @@ -58,13 +62,16 @@ def setup(): _zoph_configure('maps.provider', 'osm') -def _get_db_name(): +def _get_db_config(): """Return the name of the database configured by dbconfig.""" config = configparser.ConfigParser() - with open('/etc/zoph.ini', 'r', encoding='utf-8') as file_handle: + with DB_CONF.open('r', encoding='utf-8') as file_handle: config.read_file(file_handle) - return config['zoph']['db_name'].strip('"') + return { + 'db_name': config['zoph']['db_name'].strip('"'), + 'db_user': config['zoph']['db_user'].strip('"'), + } @privileged @@ -88,8 +95,8 @@ def set_configuration(enable_osm: bool | None = None, query = f"UPDATE zoph_users SET user_name='{admin_user}' \ WHERE user_name='admin';" - subprocess.run(['mysql', _get_db_name()], input=query.encode(), - check=True) + subprocess.run(['mysql', _get_db_config()['db_name']], + input=query.encode(), check=True) @privileged @@ -107,7 +114,7 @@ def dump_database(): May be called when app is disabled. """ with action_utils.service_ensure_running('mysql'): - db_name = _get_db_name() + db_name = _get_db_config()['db_name'] os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True) with open(DB_BACKUP_FILE, 'w', encoding='utf-8') as db_backup_file: subprocess.run(['mysqldump', db_name], stdout=db_backup_file, @@ -121,9 +128,30 @@ def restore_database(): May be called when app is disabled. """ with action_utils.service_ensure_running('mysql'): - db_name = _get_db_name() + db_name = _get_db_config()['db_name'] subprocess.run(['mysqladmin', '--force', 'drop', db_name], check=False) subprocess.run(['mysqladmin', 'create', db_name], check=True) with open(DB_BACKUP_FILE, 'r', encoding='utf-8') as db_restore_file: subprocess.run(['mysql', db_name], stdin=db_restore_file, check=True) + + +@privileged +def uninstall(): + """Drop database, database user and database configuration. + + May be called when app is disabled. + """ + with action_utils.service_ensure_running('mysql'): + try: + config = _get_db_config() + subprocess.run( + ['mysqladmin', '--force', 'drop', config['db_name']], + check=False) + + query = f'DROP USER IF EXISTS {config["db_user"]}@localhost;' + subprocess.run(['mysql'], input=query.encode(), check=False) + except FileNotFoundError: # Database configuration not found + pass + + DB_CONF.unlink(missing_ok=True) From ec52d9bed93960825e3be410064bbcdb6b47e8ad Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 14:57:02 -0800 Subject: [PATCH 23/63] daemon: Added method to ensure a daemon is running in component This will help apps like zoph that need to have database server running to install or upgrade a package. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/daemon.py | 15 +++++++++++++++ plinth/tests/test_daemon.py | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/plinth/daemon.py b/plinth/daemon.py index dad74d8d0..ae946800d 100644 --- a/plinth/daemon.py +++ b/plinth/daemon.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later """Component for managing a background daemon or any systemd unit.""" +import contextlib import socket import subprocess @@ -86,6 +87,20 @@ class Daemon(app.LeaderComponent): """Return whether the daemon/unit is running.""" return action_utils.service_is_running(self.unit) + @contextlib.contextmanager + def ensure_running(self): + """Ensure a service is running and return to previous state.""" + from plinth.privileged import service as service_privileged + starting_state = self.is_running() + if not starting_state: + service_privileged.enable(self.unit) + + try: + yield starting_state + finally: + if not starting_state: + service_privileged.disable(self.unit) + def diagnose(self) -> list[DiagnosticCheck]: """Check if the daemon is running and listening on expected ports. diff --git a/plinth/tests/test_daemon.py b/plinth/tests/test_daemon.py index d6cfcff69..bdf74d3d6 100644 --- a/plinth/tests/test_daemon.py +++ b/plinth/tests/test_daemon.py @@ -138,6 +138,44 @@ def test_is_running(service_is_running, daemon): assert not daemon.is_running() +@patch('plinth.app.apps_init') +@patch('plinth.action_utils.service_is_running') +@patch('subprocess.run') +@patch('subprocess.call') +def test_ensure_running(subprocess_call, subprocess_run, service_is_running, + apps_init, app_list, mock_privileged, daemon): + """Test that checking that the daemon is running works.""" + service_is_running.return_value = True + with daemon.ensure_running() as starting_state: + assert starting_state + assert not subprocess_call.called + assert not subprocess_run.called + + assert not subprocess_call.called + assert not subprocess_run.called + + service_is_running.return_value = False + with daemon.ensure_running() as starting_state: + assert not starting_state + assert subprocess_run.mock_calls == [ + call(['systemctl', 'start', 'test-unit'], + stdout=subprocess.DEVNULL, check=False) + ] + assert subprocess_call.mock_calls == [ + call(['systemctl', 'enable', 'test-unit']) + ] + subprocess_run.reset_mock() + subprocess_call.reset_mock() + + assert subprocess_run.mock_calls == [ + call(['systemctl', 'stop', 'test-unit'], stdout=subprocess.DEVNULL, + check=False) + ] + assert subprocess_call.mock_calls == [ + call(['systemctl', 'disable', 'test-unit']) + ] + + @patch('plinth.action_utils.service_is_running') @patch('plinth.daemon.diagnose_port_listening') def test_diagnose(port_listening, service_is_running, daemon): From c341a531ddea818fcba301169be2ee176590b6d1 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 14:58:03 -0800 Subject: [PATCH 24/63] zoph: Ensure that database server is running when setting up app When mysql server is not running, app installation fails. Similarly the setup process will fail when app is being upgrade and database upgrade needs to be performed. So, ensure that database server is running before attempting install/upgrade of app. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/zoph/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plinth/modules/zoph/__init__.py b/plinth/modules/zoph/__init__.py index 0197788a6..1008272dc 100644 --- a/plinth/modules/zoph/__init__.py +++ b/plinth/modules/zoph/__init__.py @@ -102,7 +102,11 @@ class ZophApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" privileged.pre_install() - super().setup(old_version) + with self.get_component('shared-daemon-zoph-mysql').ensure_running(): + # Database needs to be running for successful initialization or + # upgrade of zoph database. + super().setup(old_version) + privileged.setup() if not old_version: self.enable() From d615ff107ea2e1bc9eb22694474992a1e67b5dee Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 15:23:15 -0800 Subject: [PATCH 25/63] wordpress: Fix backup, restore and uninstall when db is not running Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/wordpress/privileged.py | 27 ++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/plinth/modules/wordpress/privileged.py b/plinth/modules/wordpress/privileged.py index dcb191562..a358a9687 100644 --- a/plinth/modules/wordpress/privileged.py +++ b/plinth/modules/wordpress/privileged.py @@ -144,21 +144,23 @@ def is_public() -> bool: def dump_database(): """Dump database to file.""" _db_backup_file.parent.mkdir(parents=True, exist_ok=True) - with _db_backup_file.open('w', encoding='utf-8') as file_handle: - subprocess.run([ - 'mysqldump', '--add-drop-database', '--add-drop-table', - '--add-drop-trigger', '--user', 'root', '--databases', DB_NAME - ], stdout=file_handle, check=True) + with action_utils.service_ensure_running('mysql'): + with _db_backup_file.open('w', encoding='utf-8') as file_handle: + subprocess.run([ + 'mysqldump', '--add-drop-database', '--add-drop-table', + '--add-drop-trigger', '--user', 'root', '--databases', DB_NAME + ], stdout=file_handle, check=True) @privileged def restore_database(): """Restore database from file.""" - with _db_backup_file.open('r', encoding='utf-8') as file_handle: - subprocess.run(['mysql', '--user', 'root'], stdin=file_handle, - check=True) + with action_utils.service_ensure_running('mysql'): + with _db_backup_file.open('r', encoding='utf-8') as file_handle: + subprocess.run(['mysql', '--user', 'root'], stdin=file_handle, + check=True) - _set_privileges(DB_HOST, DB_NAME, DB_USER, _read_db_password()) + _set_privileges(DB_HOST, DB_NAME, DB_USER, _read_db_password()) def _read_db_password(): @@ -188,6 +190,7 @@ def uninstall(): def _drop_database(): """Drop the mysql database that was created during install.""" - query = f'''DROP DATABASE {DB_NAME};''' - subprocess.run(['mysql', '--user', 'root'], input=query.encode(), - check=True) + with action_utils.service_ensure_running('mysql'): + query = f'''DROP DATABASE {DB_NAME};''' + subprocess.run(['mysql', '--user', 'root'], input=query.encode(), + check=True) From f0ff0c181b4eac4879ea746ba32a3dc8c7441773 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 15:32:03 -0800 Subject: [PATCH 26/63] wordpress: Drop database user when app is uninstalled Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/wordpress/privileged.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plinth/modules/wordpress/privileged.py b/plinth/modules/wordpress/privileged.py index a358a9687..32df4ec52 100644 --- a/plinth/modules/wordpress/privileged.py +++ b/plinth/modules/wordpress/privileged.py @@ -183,14 +183,18 @@ def _load_augeas(): @privileged def uninstall(): """Remove config files and drop database.""" - _drop_database() + _drop_database(DB_HOST, DB_NAME, DB_USER) for file_ in [_public_access_file, _config_file_path, _db_file_path]: file_.unlink(missing_ok=True) -def _drop_database(): +def _drop_database(db_host, db_name, db_user): """Drop the mysql database that was created during install.""" with action_utils.service_ensure_running('mysql'): - query = f'''DROP DATABASE {DB_NAME};''' + query = f"DROP DATABASE {db_name};" subprocess.run(['mysql', '--user', 'root'], input=query.encode(), - check=True) + check=False) + + query = f"DROP USER IF EXISTS {db_user}@{db_host};" + subprocess.run(['mysql', '--user', 'root'], input=query.encode(), + check=False) From d23ceb70500b48d7b28f8680cd723d6990a0e2dc Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 16:38:19 -0800 Subject: [PATCH 27/63] tests: functional: Uninstall app after backup and before restore Closes: #2353. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/tests/functional/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index 2f86dae3a..b5f232a86 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -715,6 +715,9 @@ class BaseAppTests: def test_backup_restore(self, session_browser): """Test that backup and restore operations work on the app.""" backup_create(session_browser, self.app_name, 'test_' + self.app_name) + if self.can_uninstall: + uninstall(session_browser, self.app_name) + backup_restore(session_browser, self.app_name, 'test_' + self.app_name) self.assert_app_running(session_browser) From 7d4c5650f4a0dca06c76c3d804266ed63bc08a88 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 16:57:54 -0800 Subject: [PATCH 28/63] zoph: Restore database password to old value after restore op. Fixes: #2346. Tests: - Without the patch, install zoph, take a backup. Note the db password in /etc/zoph.ini. Uninstall zoph. Install it. Note that db password changed. Restore from previous backup. Note that password has been restored to old value and zoph is unable to connect to database. - With the patch, repeat the test and notice zoph works after restore. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/zoph/privileged.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plinth/modules/zoph/privileged.py b/plinth/modules/zoph/privileged.py index 0c3087cad..2f5655c88 100644 --- a/plinth/modules/zoph/privileged.py +++ b/plinth/modules/zoph/privileged.py @@ -69,8 +69,10 @@ def _get_db_config(): config.read_file(file_handle) return { + 'db_host': config['zoph']['db_host'].strip('"'), 'db_name': config['zoph']['db_name'].strip('"'), 'db_user': config['zoph']['db_user'].strip('"'), + 'db_pass': config['zoph']['db_pass'].strip('"'), } @@ -129,12 +131,19 @@ def restore_database(): """ with action_utils.service_ensure_running('mysql'): db_name = _get_db_config()['db_name'] + db_user = _get_db_config()['db_user'] + db_host = _get_db_config()['db_host'] + db_pass = _get_db_config()['db_pass'] subprocess.run(['mysqladmin', '--force', 'drop', db_name], check=False) subprocess.run(['mysqladmin', 'create', db_name], check=True) with open(DB_BACKUP_FILE, 'r', encoding='utf-8') as db_restore_file: subprocess.run(['mysql', db_name], stdin=db_restore_file, check=True) + # Set the password for user from restored configuration + query = f'ALTER USER {db_user}@{db_host} IDENTIFIED BY "{db_pass}";' + subprocess.run(['mysql'], input=query.encode(), check=True) + @privileged def uninstall(): From 8096c14b14dd2cac000d30a0605f57b268592c08 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 17:03:54 -0800 Subject: [PATCH 29/63] wordpress: tests: Uninstall app after backup and before restore Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/wordpress/tests/test_functional.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plinth/modules/wordpress/tests/test_functional.py b/plinth/modules/wordpress/tests/test_functional.py index 9cbc5cb2d..0042ae427 100644 --- a/plinth/modules/wordpress/tests/test_functional.py +++ b/plinth/modules/wordpress/tests/test_functional.py @@ -80,6 +80,7 @@ def test_backup(session_browser): _write_post(session_browser, 'FunctionalTest') functional.backup_create(session_browser, 'wordpress', 'test_wordpress') _delete_post(session_browser, 'FunctionalTest') + functional.uninstall(session_browser, 'wordpress') functional.backup_restore(session_browser, 'wordpress', 'test_wordpress') assert _get_post(session_browser, 'FunctionalTest') From 5dbf8908812e591a85a3aa82022f283eabfb3104 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Fri, 8 Mar 2024 19:38:59 -0800 Subject: [PATCH 30/63] tests: functional: Refactor install/setup fixture for apps - Fixes an issue with zoph not being setup after uninstall+install setup and makes a test pass. - Some failures exist but don't seem related to this change. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/matrixsynapse/tests/test_functional.py | 5 ++++- plinth/modules/mediawiki/tests/test_functional.py | 9 +++------ plinth/modules/shaarli/tests/test_functional.py | 9 +++------ plinth/modules/shadowsocks/tests/test_functional.py | 8 +++----- .../shadowsocksserver/tests/test_functional.py | 8 +++----- plinth/modules/zoph/tests/test_functional.py | 11 +++++------ plinth/tests/functional/__init__.py | 8 ++++++-- 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/plinth/modules/matrixsynapse/tests/test_functional.py b/plinth/modules/matrixsynapse/tests/test_functional.py index 9a57103fd..b1bc4e3ce 100644 --- a/plinth/modules/matrixsynapse/tests/test_functional.py +++ b/plinth/modules/matrixsynapse/tests/test_functional.py @@ -21,7 +21,10 @@ class TestMatrixSynapseApp(functional.BaseAppTests): """Setup the app.""" functional.login(session_browser) functional.set_domain_name(session_browser, 'mydomain.example') - functional.install(session_browser, self.app_name) + + def install_and_setup(self, session_browser): + """Install the app and run setup.""" + super().install_and_setup(session_browser) functional.app_select_domain_name(session_browser, self.app_name, 'mydomain.example') diff --git a/plinth/modules/mediawiki/tests/test_functional.py b/plinth/modules/mediawiki/tests/test_functional.py index b82afdc2e..a01d0faeb 100644 --- a/plinth/modules/mediawiki/tests/test_functional.py +++ b/plinth/modules/mediawiki/tests/test_functional.py @@ -20,12 +20,9 @@ class TestMediawikiApp(functional.BaseAppTests): has_service = False has_web = True - @pytest.fixture(scope='class', autouse=True) - def fixture_setup(self, session_browser): - """Setup the app.""" - functional.login(session_browser) - functional.install(session_browser, 'mediawiki') - functional.app_enable(session_browser, 'mediawiki') + def install_and_setup(self, session_browser): + """Install the app and run setup.""" + super().install_and_setup(session_browser) _set_domain(session_browser) _set_admin_password(session_browser, 'whatever123') diff --git a/plinth/modules/shaarli/tests/test_functional.py b/plinth/modules/shaarli/tests/test_functional.py index 4a1cb4fdf..b756a8bf9 100644 --- a/plinth/modules/shaarli/tests/test_functional.py +++ b/plinth/modules/shaarli/tests/test_functional.py @@ -17,12 +17,9 @@ class TestShaarliApp(functional.BaseAppTests): has_service = False has_web = True - @pytest.fixture(scope='class', autouse=True) - def fixture_setup(self, session_browser): - """Setup the app.""" - functional.login(session_browser) - functional.install(session_browser, self.app_name) - functional.app_enable(session_browser, self.app_name) + def install_and_setup(self, session_browser): + """Install the app and set it up if needed.""" + super().install_and_setup(session_browser) self._shaarli_is_setup(session_browser) def _shaarli_is_setup(self, session_browser): diff --git a/plinth/modules/shadowsocks/tests/test_functional.py b/plinth/modules/shadowsocks/tests/test_functional.py index 87bcda6e0..1ed8fc38e 100644 --- a/plinth/modules/shadowsocks/tests/test_functional.py +++ b/plinth/modules/shadowsocks/tests/test_functional.py @@ -15,11 +15,9 @@ class TestShadowsocksApp(functional.BaseAppTests): has_service = True has_web = False - @pytest.fixture(scope='class', autouse=True) - def fixture_setup(self, session_browser): - """Setup the app.""" - functional.login(session_browser) - functional.install(session_browser, 'shadowsocks') + def install_and_setup(self, session_browser): + """Install the app and run setup.""" + super().install_and_setup(session_browser) _configure(session_browser, 'example.com', 'fakepassword') @pytest.mark.backups diff --git a/plinth/modules/shadowsocksserver/tests/test_functional.py b/plinth/modules/shadowsocksserver/tests/test_functional.py index c270bc163..4b0cc2c07 100644 --- a/plinth/modules/shadowsocksserver/tests/test_functional.py +++ b/plinth/modules/shadowsocksserver/tests/test_functional.py @@ -15,11 +15,9 @@ class TestShadowsocksServerApp(functional.BaseAppTests): has_service = True has_web = False - @pytest.fixture(scope='class', autouse=True) - def fixture_setup(self, session_browser): - """Setup the app.""" - functional.login(session_browser) - functional.install(session_browser, 'shadowsocksserver') + def install_and_setup(self, session_browser): + """Install the app and run setup.""" + super().install_and_setup(session_browser) _configure(session_browser, 'fakepassword') @pytest.mark.backups diff --git a/plinth/modules/zoph/tests/test_functional.py b/plinth/modules/zoph/tests/test_functional.py index 62fa7f82c..1b34c2abe 100644 --- a/plinth/modules/zoph/tests/test_functional.py +++ b/plinth/modules/zoph/tests/test_functional.py @@ -15,17 +15,16 @@ class TestZophApp(functional.BaseAppTests): has_service = False has_web = True - @pytest.fixture(scope='class', autouse=True) - def fixture_setup(self, session_browser): - """Setup the app.""" - functional.login(session_browser) - functional.install(session_browser, self.app_name) + def install_and_setup(self, session_browser): + """Install the app and run setup.""" + super().install_and_setup(session_browser) self._zoph_is_setup(session_browser) def _zoph_is_setup(self, session_browser): """Click setup button on the setup page.""" functional.nav_to_module(session_browser, self.app_name) - functional.submit(session_browser, form_class='form-configuration') + if session_browser.find_by_css('.form-configuration'): + functional.submit(session_browser, form_class='form-configuration') def assert_app_running(self, session_browser): assert functional.app_is_enabled(session_browser, self.app_name) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index b5f232a86..e4349cf42 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -675,11 +675,15 @@ class BaseAppTests: if self.has_web: assert not is_available(session_browser, self.app_name) + def install_and_setup(self, session_browser): + """Install the app and set it up if needed.""" + install(session_browser, self.app_name) + @pytest.fixture(autouse=True) def fixture_background(self, session_browser): """Login, install, and enable the app.""" login(session_browser) - install(session_browser, self.app_name) + self.install_and_setup(session_browser) app_enable(session_browser, self.app_name) yield login(session_browser) @@ -728,4 +732,4 @@ class BaseAppTests: uninstall(session_browser, self.app_name) assert not is_installed(session_browser, self.app_name) - install(session_browser, self.app_name) + self.install_and_setup(session_browser) From f9c624562aa141fe36ff247bd96ad09de2535f1e Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 11 Mar 2024 15:17:03 -0700 Subject: [PATCH 31/63] wordpress: Fix minor issue in restoring database - Overlooked in !2454. Tests: - Take a backup of wordpress app and disable it. Restore from the backup succeeds after that. Signed-off-by: Sunil Mohan Adapa --- plinth/modules/wordpress/privileged.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plinth/modules/wordpress/privileged.py b/plinth/modules/wordpress/privileged.py index 32df4ec52..0b5c92f72 100644 --- a/plinth/modules/wordpress/privileged.py +++ b/plinth/modules/wordpress/privileged.py @@ -160,7 +160,7 @@ def restore_database(): subprocess.run(['mysql', '--user', 'root'], stdin=file_handle, check=True) - _set_privileges(DB_HOST, DB_NAME, DB_USER, _read_db_password()) + _set_privileges(DB_HOST, DB_NAME, DB_USER, _read_db_password()) def _read_db_password(): From d468ca2250166ab3117c9d66472b6214f552f950 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Mon, 11 Mar 2024 20:11:25 -0400 Subject: [PATCH 32/63] locale: Update translation strings Signed-off-by: James Valleroy --- plinth/locale/ar/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/ar_SA/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/be/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/bg/LC_MESSAGES/django.po | 240 +++++++++---------- plinth/locale/bn/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/cs/LC_MESSAGES/django.po | 236 +++++++++---------- plinth/locale/da/LC_MESSAGES/django.po | 246 ++++++++++---------- plinth/locale/de/LC_MESSAGES/django.po | 242 +++++++++---------- plinth/locale/django.pot | 234 +++++++++---------- plinth/locale/el/LC_MESSAGES/django.po | 246 ++++++++++---------- plinth/locale/es/LC_MESSAGES/django.po | 238 +++++++++---------- plinth/locale/fa/LC_MESSAGES/django.po | 246 ++++++++++---------- plinth/locale/fake/LC_MESSAGES/django.po | 246 ++++++++++---------- plinth/locale/fr/LC_MESSAGES/django.po | 242 +++++++++---------- plinth/locale/gl/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/gu/LC_MESSAGES/django.po | 242 +++++++++---------- plinth/locale/hi/LC_MESSAGES/django.po | 246 ++++++++++---------- plinth/locale/hu/LC_MESSAGES/django.po | 238 +++++++++---------- plinth/locale/id/LC_MESSAGES/django.po | 238 +++++++++---------- plinth/locale/it/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/ja/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/kn/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/lt/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/lv/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/nb/LC_MESSAGES/django.po | 236 +++++++++---------- plinth/locale/nl/LC_MESSAGES/django.po | 238 +++++++++---------- plinth/locale/pl/LC_MESSAGES/django.po | 246 ++++++++++---------- plinth/locale/pt/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/ru/LC_MESSAGES/django.po | 240 +++++++++---------- plinth/locale/si/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/sl/LC_MESSAGES/django.po | 242 +++++++++---------- plinth/locale/sq/LC_MESSAGES/django.po | 242 +++++++++---------- plinth/locale/sr/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/sv/LC_MESSAGES/django.po | 242 +++++++++---------- plinth/locale/ta/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/te/LC_MESSAGES/django.po | 236 +++++++++---------- plinth/locale/tr/LC_MESSAGES/django.po | 242 +++++++++---------- plinth/locale/uk/LC_MESSAGES/django.po | 240 +++++++++---------- plinth/locale/vi/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/zh_Hans/LC_MESSAGES/django.po | 234 +++++++++---------- plinth/locale/zh_Hant/LC_MESSAGES/django.po | 234 +++++++++---------- 41 files changed, 4881 insertions(+), 4881 deletions(-) diff --git a/plinth/locale/ar/LC_MESSAGES/django.po b/plinth/locale/ar/LC_MESSAGES/django.po index 63da4475c..89d36d213 100644 --- a/plinth/locale/ar/LC_MESSAGES/django.po +++ b/plinth/locale/ar/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2023-10-19 06:18+0000\n" "Last-Translator: Shaik \n" "Language-Team: Arabic http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6168,7 +6168,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6311,7 +6311,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6320,20 +6320,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6671,14 +6671,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6686,25 +6686,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6713,30 +6713,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6745,57 +6722,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7277,7 +7277,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7290,7 +7290,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7298,11 +7298,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7356,99 +7356,99 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "حدث خطأ أثناء تثبيت التطبيق: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "حدث خطأ أثناء تثبيت التطبيق: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "ثُبت التطبيق." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "حدث خطأ أثناء تثبيت التطبيق: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "خطأ أثناء تثبيت التطبيق: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "ثُبت التطبيق." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7803,11 +7803,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/ar_SA/LC_MESSAGES/django.po b/plinth/locale/ar_SA/LC_MESSAGES/django.po index 617371d1c..a50e19ba9 100644 --- a/plinth/locale/ar_SA/LC_MESSAGES/django.po +++ b/plinth/locale/ar_SA/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2020-06-10 15:41+0000\n" "Last-Translator: aiman an \n" "Language-Team: Arabic (Saudi Arabia) http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6173,7 +6173,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6316,7 +6316,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "خطأ في تثبيت التطبيق:{error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6325,20 +6325,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6676,14 +6676,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6691,25 +6691,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6718,30 +6718,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6750,57 +6727,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7282,7 +7282,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7295,7 +7295,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7303,11 +7303,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7361,99 +7361,99 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "خطأ في تثبيت التطبيق :{string}{details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "خطأ في تثبيت التطبيق :{string}{details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "خطأ في تثبيت التطبيق:{error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "خطأ في تثبيت التطبيق:{error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "تم تثبيت التطبيق." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "خطأ في تثبيت التطبيق:{error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "خطأ في تثبيت التطبيق :{string}{details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "خطأ في تثبيت التطبيق:{error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "تم تثبيت التطبيق." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7808,11 +7808,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/be/LC_MESSAGES/django.po b/plinth/locale/be/LC_MESSAGES/django.po index a6f7558d3..6819e1e1b 100644 --- a/plinth/locale/be/LC_MESSAGES/django.po +++ b/plinth/locale/be/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -25,27 +25,27 @@ msgstr "" msgid "FreedomBox" msgstr "" -#: daemon.py:105 +#: daemon.py:122 #, python-brace-format msgid "Service {service_name} is running" msgstr "" -#: daemon.py:164 +#: daemon.py:218 #, python-brace-format msgid "Listening on {kind} port {listen_address}:{port}" msgstr "" -#: daemon.py:167 +#: daemon.py:221 #, python-brace-format msgid "Listening on {kind} port {port}" msgstr "" -#: daemon.py:236 +#: daemon.py:291 #, python-brace-format msgid "Connect to {host}:{port}" msgstr "" -#: daemon.py:240 +#: daemon.py:299 #, python-brace-format msgid "Cannot connect to {host}:{port}" msgstr "" @@ -111,12 +111,12 @@ msgstr "" msgid "{box_name} Web Interface (Plinth)" msgstr "" -#: modules/apache/components.py:154 +#: modules/apache/components.py:159 #, python-brace-format msgid "Access URL {url} on tcp{kind}" msgstr "" -#: modules/apache/components.py:157 +#: modules/apache/components.py:162 #, python-brace-format msgid "Access URL {url}" msgstr "" @@ -746,7 +746,7 @@ msgid "Permissions for anonymous users, who have not provided a password." msgstr "" #: modules/bepasty/forms.py:27 modules/bepasty/templates/bepasty.html:30 -#: modules/users/forms.py:110 modules/users/forms.py:233 +#: modules/users/forms.py:91 msgid "Permissions" msgstr "" @@ -1318,77 +1318,77 @@ msgstr "" msgid "Bittorrent client written in Python/PyGTK" msgstr "" -#: modules/diagnostics/__init__.py:27 +#: modules/diagnostics/__init__.py:28 msgid "" "The system diagnostic test will run a number of checks on your system to " "confirm that applications and services are working as expected." msgstr "" -#: modules/diagnostics/__init__.py:51 modules/diagnostics/__init__.py:236 +#: modules/diagnostics/__init__.py:52 modules/diagnostics/__init__.py:238 msgid "Diagnostics" msgstr "" -#: modules/diagnostics/__init__.py:95 +#: modules/diagnostics/__init__.py:96 msgid "passed" msgstr "" -#: modules/diagnostics/__init__.py:96 modules/networks/views.py:50 +#: modules/diagnostics/__init__.py:97 modules/networks/views.py:50 msgid "failed" msgstr "" -#: modules/diagnostics/__init__.py:97 +#: modules/diagnostics/__init__.py:98 msgid "error" msgstr "" -#: modules/diagnostics/__init__.py:98 +#: modules/diagnostics/__init__.py:99 msgid "warning" msgstr "" #. Translators: This is the unit of computer storage Mebibyte similar to #. Megabyte. -#: modules/diagnostics/__init__.py:202 +#: modules/diagnostics/__init__.py:204 msgid "MiB" msgstr "" #. Translators: This is the unit of computer storage Gibibyte similar to #. Gigabyte. -#: modules/diagnostics/__init__.py:207 +#: modules/diagnostics/__init__.py:209 msgid "GiB" msgstr "" -#: modules/diagnostics/__init__.py:214 +#: modules/diagnostics/__init__.py:216 msgid "You should disable some apps to reduce memory usage." msgstr "" -#: modules/diagnostics/__init__.py:219 +#: modules/diagnostics/__init__.py:221 msgid "You should not install any new apps on this system." msgstr "" -#: modules/diagnostics/__init__.py:231 +#: modules/diagnostics/__init__.py:233 #, no-python-format, python-brace-format msgid "" "System is low on memory: {percent_used}% used, {memory_available} " "{memory_available_unit} free. {advice_message}" msgstr "" -#: modules/diagnostics/__init__.py:233 +#: modules/diagnostics/__init__.py:235 msgid "Low Memory" msgstr "" -#: modules/diagnostics/__init__.py:264 +#: modules/diagnostics/__init__.py:266 msgid "Running diagnostics" msgstr "" -#: modules/diagnostics/__init__.py:307 +#: modules/diagnostics/__init__.py:309 #, no-python-format, python-brace-format msgid "Found {issue_count} issues during routine tests." msgstr "" -#: modules/diagnostics/__init__.py:308 +#: modules/diagnostics/__init__.py:310 msgid "Diagnostics results" msgstr "" -#: modules/diagnostics/__init__.py:313 +#: modules/diagnostics/__init__.py:315 msgid "Go to diagnostics results" msgstr "" @@ -1464,7 +1464,7 @@ msgstr "" msgid "Result" msgstr "" -#: modules/diagnostics/views.py:107 +#: modules/diagnostics/views.py:111 msgid "Diagnostic Test" msgstr "" @@ -1588,7 +1588,7 @@ msgid "Use HTTP basic authentication" msgstr "" #: modules/dynamicdns/forms.py:88 modules/networks/forms.py:207 -#: modules/users/forms.py:67 +#: modules/users/forms.py:117 msgid "Username" msgstr "" @@ -1956,29 +1956,29 @@ msgstr "" msgid "Firewall" msgstr "" -#: modules/firewall/__init__.py:271 +#: modules/firewall/__init__.py:272 msgid "Default zone is external" msgstr "" -#: modules/firewall/__init__.py:280 +#: modules/firewall/__init__.py:282 msgid "Firewall backend is nftables" msgstr "" -#: modules/firewall/__init__.py:293 +#: modules/firewall/__init__.py:296 msgid "Direct passthrough rules exist" msgstr "" -#: modules/firewall/components.py:136 +#: modules/firewall/components.py:139 #, python-brace-format msgid "Port {name} ({details}) available for internal networks" msgstr "" -#: modules/firewall/components.py:147 +#: modules/firewall/components.py:153 #, python-brace-format msgid "Port {name} ({details}) available for external networks" msgstr "" -#: modules/firewall/components.py:153 +#: modules/firewall/components.py:159 #, python-brace-format msgid "Port {name} ({details}) unavailable for external networks" msgstr "" @@ -2096,11 +2096,11 @@ msgstr "" msgid "Read-write access to Git repositories" msgstr "" -#: modules/gitweb/__init__.py:50 modules/gitweb/manifest.py:11 +#: modules/gitweb/__init__.py:48 modules/gitweb/manifest.py:11 msgid "Gitweb" msgstr "" -#: modules/gitweb/__init__.py:51 +#: modules/gitweb/__init__.py:49 msgid "Simple Git Hosting" msgstr "" @@ -2537,7 +2537,7 @@ msgid "I2P" msgstr "" #: modules/i2p/__init__.py:53 modules/tor/__init__.py:63 -#: modules/torproxy/__init__.py:56 +#: modules/torproxy/__init__.py:57 msgid "Anonymity Network" msgstr "" @@ -3496,19 +3496,19 @@ msgstr "" msgid "Services" msgstr "" -#: modules/networks/__init__.py:35 +#: modules/networks/__init__.py:36 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: modules/networks/__init__.py:37 +#: modules/networks/__init__.py:38 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: modules/networks/__init__.py:58 +#: modules/networks/__init__.py:59 msgid "Networks" msgstr "" @@ -4871,14 +4871,14 @@ msgid "" "network for additional anonymity if Tor app is enabled." msgstr "" -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " "access, and removing ads and other obnoxious Internet junk. " msgstr "" -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -4889,15 +4889,15 @@ msgid "" "p\">http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6161,7 +6161,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6303,7 +6303,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6312,20 +6312,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6663,14 +6663,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6678,25 +6678,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6705,30 +6705,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6737,57 +6714,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7269,7 +7269,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7282,7 +7282,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7290,11 +7290,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7348,87 +7348,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7781,11 +7781,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/bg/LC_MESSAGES/django.po b/plinth/locale/bg/LC_MESSAGES/django.po index d4d180a54..d2d17f248 100644 --- a/plinth/locale/bg/LC_MESSAGES/django.po +++ b/plinth/locale/bg/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2023-09-18 19:00+0000\n" "Last-Translator: 109247019824 \n" "Language-Team: Bulgarian popcon.debian.org. За допълнителна анонимност данните " "се изпращат през мрежата на Тор, ако приложението Тор е включено." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " "access, and removing ads and other obnoxious Internet junk. " msgstr "" -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5164,15 +5164,15 @@ msgid "" "p\">http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6491,7 +6491,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Синхронизиране на файлове" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6653,7 +6653,7 @@ msgstr "Запазване на настройки" msgid "Error configuring app: {error}" msgstr "Грешка при настройка на приложението: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6662,20 +6662,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Прокси сървър на Тор" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Прокси сървър на Тор за SOCKS" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Достъп до {url} по tcp{kind} чрез Тор" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -7057,7 +7057,7 @@ msgstr "Честото обновяване на пакети е включен msgid "Starting distribution upgrade test." msgstr "Начало на опит за обновяване на дистрибуцията." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7068,7 +7068,7 @@ msgstr "" "получи достъп, някои приложения още имат изискване потребителският профил да " "бъде част от определена група." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7080,25 +7080,25 @@ msgstr "" "администратори могат да променят приложенията и настройките на " "системата." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Потребители и групи" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Достъп до всички услуги и системни настройки" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Проверете записа на LDAP „{search_item}“" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7107,33 +7107,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "Потребителското име е заето." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Въведете валидно потребителско име." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Задължително. 150 знака или по-малко. Само латински букви, цифри и @/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Парола за удостоверяване" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"За да разрешите промяната на профила, въведете паролата на потребителя " -"„{user}“." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Грешна парола." - -#: modules/users/forms.py:112 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 " @@ -7142,21 +7116,47 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Въведете валидно потребителско име." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Задължително. 150 знака или по-малко. Само латински букви, цифри и @/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Парола за удостоверяване" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"За да разрешите промяната на профила, въведете паролата на потребителя " +"„{user}“." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Грешна парола." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Не е създаден потребител в LDAP: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Новият потребител не е добавен към групата {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Удостоверени ключове на SSH" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7167,36 +7167,36 @@ msgstr "" "няколко ключа, по един на ред. Празните редове и редовете, започващи с #, ще " "бъдат пренебрегнати." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Потребителят на LDAP не е преименуван." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Потребителят не е премахнат от групата." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Потребителят не е добавен към групата." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Ключовете на SSH не са зададени." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Състоянието на потребителя не е променено." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Паролата на потребителя на LDAP не е променена." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Новият потребител не е добавен към администраторската група: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Профилът е създаден и вече сте влезли" @@ -7690,7 +7690,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7703,7 +7703,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7711,11 +7711,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7772,87 +7772,87 @@ msgstr "Готово: {name}" msgid "Package {package_expression} is not available for install" msgstr "Пакетът „{expression}“ е недостъпен за инсталиране" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Времето за изчакване на диспечера на пакети е изтекло" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Инсталиране на приложение" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Обновяване на приложение" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Грешка при инсталиране на приложението: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Грешка при обновяване на приложението: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Грешка при инсталиране на приложението: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Грешка при обновяване на приложението: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "Приложението е инсталирано." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Приложението е обновено" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Премахване на приложение" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Грешка при премахване на приложението: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Грешка при премахване на приложението: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Приложението е премахнато." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Обновяване на пакетите на приложението" @@ -8217,11 +8217,11 @@ msgstr "" "Всички данни и настройки на приложението ще бъдат загубени. Приложението " "може да бъде инсталирано отново." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Настройките не са променени" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "преди премахване на {app_id}" diff --git a/plinth/locale/bn/LC_MESSAGES/django.po b/plinth/locale/bn/LC_MESSAGES/django.po index 8f107a0d6..b533dc3e6 100644 --- a/plinth/locale/bn/LC_MESSAGES/django.po +++ b/plinth/locale/bn/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2021-06-16 07:33+0000\n" "Last-Translator: Oymate \n" "Language-Team: Bengali http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6199,7 +6199,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6343,7 +6343,7 @@ msgstr "পছন্দসমূহ" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6352,20 +6352,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6703,14 +6703,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6718,25 +6718,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6745,30 +6745,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6777,57 +6754,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7309,7 +7309,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7322,7 +7322,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7330,11 +7330,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7388,87 +7388,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7823,11 +7823,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/cs/LC_MESSAGES/django.po b/plinth/locale/cs/LC_MESSAGES/django.po index f695f01ee..6f3204a1f 100644 --- a/plinth/locale/cs/LC_MESSAGES/django.po +++ b/plinth/locale/cs/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2023-11-20 05:11+0000\n" "Last-Translator: Jiří Podhorecký \n" "Language-Team: Czech popcon.debian.org. Odesílání " "probíhá přes síť Tor pro další anonymitu, pokud je povolena aplikace Tor." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5574,7 +5574,7 @@ msgstr "" "zlepšujícími soukromí, upravující data webových stánek a HTTP hlaviček, " "řídící přístup a odebírající reklamy a ostatní otravné Internetové smetí. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5591,15 +5591,15 @@ msgstr "" "org\">http://config.privoxy.org/ nebo http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Webová proxy" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Přistupte {url} s proxy {proxy} na tcp{kind}" @@ -7063,7 +7063,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Synchronizace souborů" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7232,7 +7232,7 @@ msgstr "Aktualizace konfigurace" msgid "Error configuring app: {error}" msgstr "Chyba při konfiguraci aplikace: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7245,20 +7245,20 @@ msgstr "" "aplikace pro přístup k internetu prostřednictvím sítě Tor. Cenzuru " "poskytovatelů internetových služeb lze obejít pomocí upstreamových mostů." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Tor Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor Socks proxy" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Přistoupit k URL adrese {url} na tcp{kind} prostřednictvím Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Potvrďte použití Tor na adrese {url} na tcp{kind}" @@ -7656,7 +7656,7 @@ msgstr "Aktivovány časté aktualizace funkcí." msgid "Starting distribution upgrade test." msgstr "Zahájení testu aktualizace distribuce." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7667,7 +7667,7 @@ msgstr "" "aby uživatelský účet byl součástí skupiny, která uživatele opravňuje k " "přístupu k aplikaci." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7679,25 +7679,25 @@ msgstr "" "nebo nastavení systému však mohou měnit pouze uživatelé skupiny admin." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Uživatelé a skupiny" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Přístup ke všem službám a nastavení systému" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Zkontrolujte LDAP položku „{search_item}“" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Zkontrolujte konfiguraci nslcd \"{key} {value}\"" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Zkontrolujte konfiguraci nsswitch \" {database}\"" @@ -7707,31 +7707,7 @@ msgid "Username is taken or is reserved." msgstr "" "Toto uživatelské jméno je už používáno někým jiným nebo vyhrazeno pro systém." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Zadejte platné uživatelské jméno." - -#: modules/users/forms.py:69 -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 @/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Autorizační heslo" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "Zadejte heslo uživatele \"{user}\" pro autorizaci změn účtu." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Neplatné heslo." - -#: modules/users/forms.py:112 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 " @@ -7745,21 +7721,45 @@ msgstr "" "skupině admin se budou moci přihlásit ke všem službám. Mohou se také " "přihlašovat do systému prostřednictvím SSH a mají práva správce (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Zadejte platné uživatelské jméno." + +#: modules/users/forms.py:119 +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 @/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Autorizační heslo" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "Zadejte heslo uživatele \"{user}\" pro autorizaci změn účtu." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Neplatné heslo." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Vytvoření uživatele LDAP se nezdařilo: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Nepodařilo se přidat nového uživatele do skupiny {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Pověřené SSH klíče" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7769,36 +7769,36 @@ msgstr "" "systému i bez zadávání hesla. Klíčů je možné vložit vícero, každý na vlastní " "řádek. Prázdné řádky a ty, které začínají na znak # budou ignorovány." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Přejmenování LDAP uživatele se nezdařilo." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Odebrání uživatele ze skupiny se nezdařilo." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Přidání uživatele do skupiny se nezdařilo." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Nepodařilo se vložit SSH klíče." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Nepodařilo se změnit stav uživatele." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Změna hesla LDAP uživatele se nezdařila." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Nepodařilo se přidat nového uživatele do skupiny admin: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Uživatelský účet vytvořen, není jste jím přihlášeni" @@ -8335,7 +8335,7 @@ msgstr "" "WordPress pouze správcům. Povolte pouze po provedení počátečního nastavení " "WordPressu." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8357,7 +8357,7 @@ msgstr "" "určitém místě. Jednotlivé fotografie lze sdílet s ostatními odesláním " "přímého odkazu." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8368,11 +8368,11 @@ msgstr "" "další uživatele musí být vytvořeny účty jak v {box_name}, tak v Zoph se " "stejným uživatelským jménem." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Organizér fotografií" @@ -8431,87 +8431,87 @@ msgstr "Dokončeno: {name}" msgid "Package {package_expression} is not available for install" msgstr "Balíček {expression} není k dispozici pro instalaci" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Balíček {package_name} je nejnovější verze ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "Instalace" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "stahování" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "změna média" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "soubor s nastaveními: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Časový limit čekání na správce balíčků" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Instalace aplikací" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Aktualizace aplikací" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Chyba instalace aplikace: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Chyba aktualizace aplikace: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Chyba při instalaci aplikace: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Chyba při aktualizaci aplikace: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "Aplikace nainstalována." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Aplikace aktualizována" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Odinstalování aplikace" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Chyba odinstalace aplikace: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Chyba při odinstalaci aplikace: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Aplikace odinstalována." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Aktualizace balíčků aplikací" @@ -8904,11 +8904,11 @@ msgstr "" "Všechna data a konfigurace aplikace budou trvale ztraceny. Aplikaci lze " "nainstalovat znovu." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Nastavení se nezměnila" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "před odinstalací {app_id}" diff --git a/plinth/locale/da/LC_MESSAGES/django.po b/plinth/locale/da/LC_MESSAGES/django.po index 0c0324505..2aae8e14f 100644 --- a/plinth/locale/da/LC_MESSAGES/django.po +++ b/plinth/locale/da/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Danish http://config.privoxy.org/ " "eller http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 #, fuzzy #| msgid "Enable Privoxy" msgid "Privoxy" msgstr "Aktiver Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 #, fuzzy #| msgid "Privoxy Web Proxy" msgid "Web Proxy" msgstr "Privoxy Webproxy" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Tilgå {url} med proxy {proxy} ved brug af tcp{kind}" @@ -7125,7 +7125,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7291,7 +7291,7 @@ msgstr "Der opstod en fejl under konfigurationen." msgid "Error configuring app: {error}" msgstr "Kunne ikke installere applikation: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7300,22 +7300,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2P Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Tilgå URL {url} ved brug af tcp{kind} via Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bekræft brug af Tor på {url} ved brug af tcp{kind}" @@ -7727,14 +7727,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "Automatisk opdatering aktiveret" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7742,25 +7742,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Brugere og Grupper" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Kontrol af LDAP-konfiguration \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7769,37 +7769,8 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid server name" -msgid "Enter a valid username." -msgstr "Ugyldigt servernavn" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Account" -msgid "Authorization Password" -msgstr "Administratorkonto" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 #, fuzzy -#| msgid "Show password" -msgid "Invalid password." -msgstr "Vis kodeord" - -#: modules/users/forms.py:112 -#, 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, " @@ -7820,23 +7791,52 @@ msgstr "" "tjenester. De kan også logge ind på systemet gennem SSH og har " "administratorprivilegier (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid server name" +msgid "Enter a valid username." +msgstr "Ugyldigt servernavn" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +#, fuzzy +#| msgid "Administrator Account" +msgid "Authorization Password" +msgstr "Administratorkonto" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Show password" +msgid "Invalid password." +msgstr "Vis kodeord" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "Kunne ikke oprette LDAP-bruger." -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" msgstr "Kunne ikke tilføje ny bruger til gruppen {group}." -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7846,39 +7846,39 @@ msgstr "" "sikkert ind på systemet uden et kodeord. Der kan defineres flere nøgler, en " "på hver linje. Tomme linjer og linjer som starter med # bliver ignoreret." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Kunne ikke omdøbe LDAP-bruger." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Kunne ikke fjerne bruger fra gruppe." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Kunne ikke tilføje bruger til gruppe." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "Kunne ikke tilføje bruger til gruppe." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Kunne ikke ændre LDAP-kodeord." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "Kunne ikke tilføje ny bruger til admin-gruppen." -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Brugerkonto oprettet, du er nu logget ind" @@ -8427,7 +8427,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8440,7 +8440,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8448,11 +8448,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -8510,103 +8510,103 @@ msgstr "Tjeneste ikke aktiv: {name}" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "Installerer" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "downloader" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "medie-ændring" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "konfigurationsfil: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Installer applikationer" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Kunne ikke installere applikation: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Kunne ikke installere applikation: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Kunne ikke installere applikation: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Kunne ikke installere applikation: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Applikation installeret." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Seneste opdatering" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Installer applikationer" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Kunne ikke installere applikation: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Kunne ikke installere applikation: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Applikation installeret." -#: setup.py:453 +#: setup.py:513 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -9008,11 +9008,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Indstilling uændret" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/de/LC_MESSAGES/django.po b/plinth/locale/de/LC_MESSAGES/django.po index aae99e23c..60cb43faa 100644 --- a/plinth/locale/de/LC_MESSAGES/django.po +++ b/plinth/locale/de/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-02-22 14:02+0000\n" "Last-Translator: Olaf Schaf \n" "Language-Team: German . Die Übermittlung erfolgt über das Tor-Netzwerk für zusätzliche " "Anonymität, wenn die Tor-App aktiviert ist." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5684,7 +5684,7 @@ msgstr "" "kontrolliert den Zugang und entfernt Werbung und anderen abscheulichen " "Internet-Müll. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5701,15 +5701,15 @@ msgstr "" "unter http://config.privoxy.org/ " "oder http://p.p einsehen." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Web Proxy" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Zugang auf {url} über Proxy {proxy} auf TCP{kind}" @@ -7205,7 +7205,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Dateisynchronisation" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7380,7 +7380,7 @@ msgstr "Aktualisieren der Konfiguration" msgid "Error configuring app: {error}" msgstr "Fehler beim Konfigurieren der App: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7394,20 +7394,20 @@ msgstr "" "Internet zuzugreifen. Die ISP-Zensur kann mit Upstream-Brücken umgangen " "werden." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Tor-Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor-Socks-Proxy" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Zugangs-URL {url} auf TCP{kind} über Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Tor-Nutzung auf {url} über TCP{kind} bestätigen" @@ -7814,7 +7814,7 @@ msgstr "Häufige Funktions-Updates aktiviert." msgid "Starting distribution upgrade test." msgstr "Start des Tests zur Aktualisierung der Distribution." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7825,7 +7825,7 @@ msgstr "" "muss ein Benutzerkonto Teil einer Gruppe sein, damit ein Benutzer auf die " "App zugreifen kann." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7837,25 +7837,25 @@ msgstr "" "dürfen nur Mitglieder der Gruppe admin Apps oder " "Systemeinstellungen ändern." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Benutzer und Gruppen" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Zugriff auf alle Anwendungen und Systemeinstellungen" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP-Eintrag „{search_item}“ prüfen" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Prüfen Sie die nslcd-Konfiguration \"{key} {value}\"" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Prüfen Sie die nsswitch-Konfiguration \"{database}\"" @@ -7864,34 +7864,7 @@ msgstr "Prüfen Sie die nsswitch-Konfiguration \"{database}\"" msgid "Username is taken or is reserved." msgstr "Benutzername wird bereits verwendet oder ist reserviert." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Einen gültigen Benutzernamen eingeben." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Erforderlich. Bis zu 150 Zeichen. Nur englische Buchstaben, Ziffern und " -"@/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Autorisierungs-Passwort" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Geben Sie das Passwort für den Benutzer „{user}“ ein, um Kontoänderungen zu " -"autorisieren." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Ungültiges Passwort." - -#: modules/users/forms.py:112 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 " @@ -7906,22 +7879,49 @@ msgstr "" "allen Diensten anmelden und sie können sich auch über SSH im System anmelden " "und besitzen Administratorrechte (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Einen gültigen Benutzernamen eingeben." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Erforderlich. Bis zu 150 Zeichen. Nur englische Buchstaben, Ziffern und " +"@/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Autorisierungs-Passwort" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Geben Sie das Passwort für den Benutzer „{user}“ ein, um Kontoänderungen zu " +"autorisieren." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Ungültiges Passwort." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Erstellen des LDAP-Benutzers ist fehlgeschlagen:{error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" "Fehler beim Hinzufügen eines neuen Benutzers zur {group}-Gruppe: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Autorisierte SSH-Schlüssel" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7932,37 +7932,37 @@ msgstr "" "eingeben, einen pro Zeile. Leerzeilen und Zeilen, die mit # beginnen, werden " "ignoriert." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Umbenennen des LDAP-Benutzers fehlgeschlagen." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Entfernen des Benutzers von der Gruppe fehlgeschlagen." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Hinzufügen eines Benutzers zur Gruppe ist fehlgeschlagen." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "SSH-Schlüssel kann nicht gesetzt werden." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Fehler beim Ändern des Benutzerstatus." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Ändern des LDAP-Benutzerpassworts ist fehlgeschlagen." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Fehler beim Hinzufügen eines neuen Benutzers zur Administratorgruppe: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Benutzerkonto wurde erstellt, Sie sind jetzt angemeldet" @@ -8514,7 +8514,7 @@ msgstr "" "Administratoren die WordPress-Website oder den Blog aufrufen. Aktivieren Sie " "diese Option erst nach der Ersteinrichtung von WordPress." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8539,7 +8539,7 @@ msgstr "" "Einzelne Fotos können mit anderen geteilt werden, indem ein direkter Link " "gesendet wird." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8550,11 +8550,11 @@ msgstr "" "Administrator in Zoph. Für zusätzliche Benutzer müssen Konten sowohl in " "{box_name} als auch in Zoph mit demselben Benutzernamen erstellt werden." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Foto-Manager" @@ -8613,87 +8613,87 @@ msgstr "Fertig: {name}" msgid "Package {package_expression} is not available for install" msgstr "Paket {package_expression} ist nicht zur Installation verfügbar" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Paket {package_name} ist die aktuellste Version ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "Installation läuft" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "herunterladen" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "Medienwechsel" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "Konfigurationsdatei: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Zeitüberschreitung beim Warten auf den Paket-Manager" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Installation der App" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Aktualisieren der App" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Fehler bei der Installation der App: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Fehler beim Aktualisieren der App: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Fehler bei der Installation der App: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Fehler beim Aktualisieren der App: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "App installiert." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "App aktualisiert" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Deinstallation der App" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Fehler bei der Deinstallation der App: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Fehler bei der Deinstallation der App: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "App deinstalliert." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Aktualisieren von App-Paketen" @@ -9090,11 +9090,11 @@ msgstr "" "Alle App-Daten und -Konfigurationen gehen dauerhaft verloren. App kann " "wieder frisch installiert werden." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Einstellung unverändert" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "vor der Deinstallation von {app_id}" diff --git a/plinth/locale/django.pot b/plinth/locale/django.pot index 63b334594..8ad1d5fcf 100644 --- a/plinth/locale/django.pot +++ b/plinth/locale/django.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -26,27 +26,27 @@ msgstr "" msgid "FreedomBox" msgstr "" -#: daemon.py:105 +#: daemon.py:122 #, python-brace-format msgid "Service {service_name} is running" msgstr "" -#: daemon.py:164 +#: daemon.py:218 #, python-brace-format msgid "Listening on {kind} port {listen_address}:{port}" msgstr "" -#: daemon.py:167 +#: daemon.py:221 #, python-brace-format msgid "Listening on {kind} port {port}" msgstr "" -#: daemon.py:236 +#: daemon.py:291 #, python-brace-format msgid "Connect to {host}:{port}" msgstr "" -#: daemon.py:240 +#: daemon.py:299 #, python-brace-format msgid "Cannot connect to {host}:{port}" msgstr "" @@ -112,12 +112,12 @@ msgstr "" msgid "{box_name} Web Interface (Plinth)" msgstr "" -#: modules/apache/components.py:154 +#: modules/apache/components.py:159 #, python-brace-format msgid "Access URL {url} on tcp{kind}" msgstr "" -#: modules/apache/components.py:157 +#: modules/apache/components.py:162 #, python-brace-format msgid "Access URL {url}" msgstr "" @@ -747,7 +747,7 @@ msgid "Permissions for anonymous users, who have not provided a password." msgstr "" #: modules/bepasty/forms.py:27 modules/bepasty/templates/bepasty.html:30 -#: modules/users/forms.py:110 modules/users/forms.py:233 +#: modules/users/forms.py:91 msgid "Permissions" msgstr "" @@ -1319,77 +1319,77 @@ msgstr "" msgid "Bittorrent client written in Python/PyGTK" msgstr "" -#: modules/diagnostics/__init__.py:27 +#: modules/diagnostics/__init__.py:28 msgid "" "The system diagnostic test will run a number of checks on your system to " "confirm that applications and services are working as expected." msgstr "" -#: modules/diagnostics/__init__.py:51 modules/diagnostics/__init__.py:236 +#: modules/diagnostics/__init__.py:52 modules/diagnostics/__init__.py:238 msgid "Diagnostics" msgstr "" -#: modules/diagnostics/__init__.py:95 +#: modules/diagnostics/__init__.py:96 msgid "passed" msgstr "" -#: modules/diagnostics/__init__.py:96 modules/networks/views.py:50 +#: modules/diagnostics/__init__.py:97 modules/networks/views.py:50 msgid "failed" msgstr "" -#: modules/diagnostics/__init__.py:97 +#: modules/diagnostics/__init__.py:98 msgid "error" msgstr "" -#: modules/diagnostics/__init__.py:98 +#: modules/diagnostics/__init__.py:99 msgid "warning" msgstr "" #. Translators: This is the unit of computer storage Mebibyte similar to #. Megabyte. -#: modules/diagnostics/__init__.py:202 +#: modules/diagnostics/__init__.py:204 msgid "MiB" msgstr "" #. Translators: This is the unit of computer storage Gibibyte similar to #. Gigabyte. -#: modules/diagnostics/__init__.py:207 +#: modules/diagnostics/__init__.py:209 msgid "GiB" msgstr "" -#: modules/diagnostics/__init__.py:214 +#: modules/diagnostics/__init__.py:216 msgid "You should disable some apps to reduce memory usage." msgstr "" -#: modules/diagnostics/__init__.py:219 +#: modules/diagnostics/__init__.py:221 msgid "You should not install any new apps on this system." msgstr "" -#: modules/diagnostics/__init__.py:231 +#: modules/diagnostics/__init__.py:233 #, no-python-format, python-brace-format msgid "" "System is low on memory: {percent_used}% used, {memory_available} " "{memory_available_unit} free. {advice_message}" msgstr "" -#: modules/diagnostics/__init__.py:233 +#: modules/diagnostics/__init__.py:235 msgid "Low Memory" msgstr "" -#: modules/diagnostics/__init__.py:264 +#: modules/diagnostics/__init__.py:266 msgid "Running diagnostics" msgstr "" -#: modules/diagnostics/__init__.py:307 +#: modules/diagnostics/__init__.py:309 #, no-python-format, python-brace-format msgid "Found {issue_count} issues during routine tests." msgstr "" -#: modules/diagnostics/__init__.py:308 +#: modules/diagnostics/__init__.py:310 msgid "Diagnostics results" msgstr "" -#: modules/diagnostics/__init__.py:313 +#: modules/diagnostics/__init__.py:315 msgid "Go to diagnostics results" msgstr "" @@ -1465,7 +1465,7 @@ msgstr "" msgid "Result" msgstr "" -#: modules/diagnostics/views.py:107 +#: modules/diagnostics/views.py:111 msgid "Diagnostic Test" msgstr "" @@ -1589,7 +1589,7 @@ msgid "Use HTTP basic authentication" msgstr "" #: modules/dynamicdns/forms.py:88 modules/networks/forms.py:207 -#: modules/users/forms.py:67 +#: modules/users/forms.py:117 msgid "Username" msgstr "" @@ -1957,29 +1957,29 @@ msgstr "" msgid "Firewall" msgstr "" -#: modules/firewall/__init__.py:271 +#: modules/firewall/__init__.py:272 msgid "Default zone is external" msgstr "" -#: modules/firewall/__init__.py:280 +#: modules/firewall/__init__.py:282 msgid "Firewall backend is nftables" msgstr "" -#: modules/firewall/__init__.py:293 +#: modules/firewall/__init__.py:296 msgid "Direct passthrough rules exist" msgstr "" -#: modules/firewall/components.py:136 +#: modules/firewall/components.py:139 #, python-brace-format msgid "Port {name} ({details}) available for internal networks" msgstr "" -#: modules/firewall/components.py:147 +#: modules/firewall/components.py:153 #, python-brace-format msgid "Port {name} ({details}) available for external networks" msgstr "" -#: modules/firewall/components.py:153 +#: modules/firewall/components.py:159 #, python-brace-format msgid "Port {name} ({details}) unavailable for external networks" msgstr "" @@ -2097,11 +2097,11 @@ msgstr "" msgid "Read-write access to Git repositories" msgstr "" -#: modules/gitweb/__init__.py:50 modules/gitweb/manifest.py:11 +#: modules/gitweb/__init__.py:48 modules/gitweb/manifest.py:11 msgid "Gitweb" msgstr "" -#: modules/gitweb/__init__.py:51 +#: modules/gitweb/__init__.py:49 msgid "Simple Git Hosting" msgstr "" @@ -2538,7 +2538,7 @@ msgid "I2P" msgstr "" #: modules/i2p/__init__.py:53 modules/tor/__init__.py:63 -#: modules/torproxy/__init__.py:56 +#: modules/torproxy/__init__.py:57 msgid "Anonymity Network" msgstr "" @@ -3497,19 +3497,19 @@ msgstr "" msgid "Services" msgstr "" -#: modules/networks/__init__.py:35 +#: modules/networks/__init__.py:36 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: modules/networks/__init__.py:37 +#: modules/networks/__init__.py:38 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: modules/networks/__init__.py:58 +#: modules/networks/__init__.py:59 msgid "Networks" msgstr "" @@ -4872,14 +4872,14 @@ msgid "" "network for additional anonymity if Tor app is enabled." msgstr "" -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " "access, and removing ads and other obnoxious Internet junk. " msgstr "" -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -4890,15 +4890,15 @@ msgid "" "p\">http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6162,7 +6162,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6304,7 +6304,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6313,20 +6313,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6664,14 +6664,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6679,25 +6679,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6706,30 +6706,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6738,57 +6715,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7270,7 +7270,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7283,7 +7283,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7291,11 +7291,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7349,87 +7349,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7782,11 +7782,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/el/LC_MESSAGES/django.po b/plinth/locale/el/LC_MESSAGES/django.po index faaa483a4..063da3809 100644 --- a/plinth/locale/el/LC_MESSAGES/django.po +++ b/plinth/locale/el/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:20+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Greek http://config.privoxy.org/ ή http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Διακομιστής μεσολάβησης διαδικτύου" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -7326,7 +7326,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Συγχρονισμός αρχείων" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7506,7 +7506,7 @@ msgstr "Παρουσιάστηκε σφάλμα κατά τη ρύθμιση π msgid "Error configuring app: {error}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7515,22 +7515,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "Tor Socks Proxy" msgid "Tor Proxy" msgstr "Tor διακομιστής μεσολάβησης τύπου socks5" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor διακομιστής μεσολάβησης τύπου socks5" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Πρόσβαση στη διεύθυνση URL {url} με tcp {kind} μέσω του Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Επιβεβαίωση χρήσης του Tor στο {url} στο προτόκολλο TCP {kind}" @@ -7951,7 +7951,7 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "Oι αυτόματες ενημερώσεις ενεργοποιήθηκαν" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 #, fuzzy #| msgid "" #| "Create and managed user accounts. These accounts serve as centralized " @@ -7968,7 +7968,7 @@ msgstr "" "είναι μέρος μιας ομάδας για να εξουσιοδοτήσουν το χρήστη να αποκτήσει " "πρόσβαση στην εφαρμογή." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7980,25 +7980,25 @@ msgstr "" "σελίδα. Ωστόσο, μόνο οι χρήστες της ομάδας admin μπορούν να " "τροποποιήσουν τις εφαρμογές ή τις ρυθμίσεις του συστήματος." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Χρήστες και ομάδες" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Πρόσβαση σε όλες τις υπηρεσίες και τις ρυθμίσεις συστήματος" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Ελέγξτε την καταχώρηση LDAP \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -8007,37 +8007,8 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "Το όνομα χρήστη είναι δεσμευμένο." -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid server name" -msgid "Enter a valid username." -msgstr "Μη έγκυρο όνομα διακομιστή" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Password" -msgid "Authorization Password" -msgstr "Κωδικός Πρόσβασης Διαχειριστή" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 #, fuzzy -#| msgid "Show password" -msgid "Invalid password." -msgstr "Εμφάνιση κωδικού" - -#: modules/users/forms.py:112 -#, 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, " @@ -8058,23 +8029,52 @@ msgstr "" "υπηρεσίες. Μπορούν επίσης να συνδεθούν στο σύστημα μέσω του SSH και να έχουν " "δικαιώματα διαχειριστή (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid server name" +msgid "Enter a valid username." +msgstr "Μη έγκυρο όνομα διακομιστή" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +#, fuzzy +#| msgid "Administrator Password" +msgid "Authorization Password" +msgstr "Κωδικός Πρόσβασης Διαχειριστή" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Show password" +msgid "Invalid password." +msgstr "Εμφάνιση κωδικού" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "Η δημιουργία χρήστη LDAP απέτυχε." -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" msgstr "Απέτυχε η προσθήκη νέου χρήστη στην ομάδα {group}." -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Εξουσιοδοτημένα κλειδιά SSH" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -8085,37 +8085,37 @@ msgstr "" "Μπορείτε να εισαγάγετε πολλαπλά κλειδιά, ένα σε κάθε γραμμή. Οι κενές " "γραμμές και οι γραμμές που ξεκινούν με # θα αγνοηθούν." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Η μετονομασία του χρήστη LDAP απέτυχε." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Απέτυχε η κατάργηση του χρήστη από την ομάδα." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Απέτυχε η προσθήκη χρήστη στην ομάδα." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Δεν ήταν δυνατό να προστεθούν τα κλειδιά SSH." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Απέτυχε η αλλαγή της κατάστασης χρήστη." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Η αλλαγή του κωδικού πρόσβασης χρήστη LDAP απέτυχε." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "Αποτυχία προσθήκης νέου χρήστη στην ομάδα διαχειριστών." -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Ο λογαριασμός χρήστη δημιουργήθηκε, τώρα είστε συνδεδεμένοι" @@ -8678,7 +8678,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8691,7 +8691,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8699,11 +8699,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -8760,105 +8760,105 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "Εγκαθίσταται" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "Λήψη" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "Αλλαγή μέσου" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "αρχείο ρυθμίσεων: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Εγκαταστήσετε Εφαρμογές" -#: setup.py:43 +#: setup.py:41 #, fuzzy #| msgid "Updating..." msgid "Updating app" msgstr "Eνημερώνεται..." -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Η εφαρμογή εγκαταστάθηκε." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Τελευταία ενημέρωση" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Εγκαταστήσετε Εφαρμογές" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Σφάλμα κατά την εγκατάσταση της εφαρμογής: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Η εφαρμογή εγκαταστάθηκε." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -9276,11 +9276,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Οι ρυθμίσεις δεν άλλαξαν" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/es/LC_MESSAGES/django.po b/plinth/locale/es/LC_MESSAGES/django.po index b66f76199..90540c4fd 100644 --- a/plinth/locale/es/LC_MESSAGES/django.po +++ b/plinth/locale/es/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-02-06 14:01+0000\n" "Last-Translator: gallegonovato \n" "Language-Team: Spanish popcon.debian.org. La transmisión se realiza a través " "de la red Tor para mayor anonimato cuando la aplicación Tor está habilitada." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5605,7 +5605,7 @@ msgstr "" "cabeceras HTTP, controlar el acceso y eliminar publicidad y otra basura de " "Internet. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5622,15 +5622,15 @@ msgstr "" "config.privoxy.org\">http://config.privoxy.org/ o http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Proxy Web" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Acceso a {url} con proxy {proxy} en tcp {kind}" @@ -7102,7 +7102,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Sincronización de archivos" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7275,7 +7275,7 @@ msgstr "Actualizando la configuración" msgid "Error configuring app: {error}" msgstr "Error al configurar la aplicación: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7288,20 +7288,20 @@ msgstr "" "utilizado por varias aplicaciones para acceder a Internet a través de la red " "Tor. La censura del ISP puede eludirse usando puentes ascendentes." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Proxy de Tor" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Proxy Socks para Tor" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Acceso a URL {url} sobre tcp {kind} vía Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Confirmar uso de Tor en {url} sobre tcp {kind}" @@ -7707,7 +7707,7 @@ msgstr "Las actualizaciones funcionales frecuentes están activadas." msgid "Starting distribution upgrade test." msgstr "Comenzando la prueba de la actualización de la distribución." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7718,7 +7718,7 @@ msgstr "" "requieren que además la cuenta de usuario conste en un grupo para " "autorizarles a acceder." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7730,25 +7730,25 @@ msgstr "" "sólo los usuarios del grupo admin pueden cambiar configuraciones de " "apps o del sistema." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Usuarias/os y grupos" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Acceso a todos los servicios y configuraciones del sistema" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Comprobar la entrada LDAP \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Comprobar la configuración de nslcd \"{key} {value}\"" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Comprueba la configuración del nsswitch \"{database}\"" @@ -7757,32 +7757,7 @@ msgstr "Comprueba la configuración del nsswitch \"{database}\"" msgid "Username is taken or is reserved." msgstr "El nombre de usuaria/o está en uso o reservado." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Indique un nombre de usuario válido." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "Obligatorio. Hasta 150 caracteres. Solo letras, números y @/./-/_ ." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Contraseña de autorización" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Introduce la contraseña del usuario \"{user}\" para autorizar modificaciones " -"en la cuenta." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Contraseña no válida." - -#: modules/users/forms.py:112 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 " @@ -7797,21 +7772,46 @@ msgstr "" "servicios, también podrán acceder al sistema por SSH con privilegios de " "administración (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Indique un nombre de usuario válido." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "Obligatorio. Hasta 150 caracteres. Solo letras, números y @/./-/_ ." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Contraseña de autorización" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Introduce la contraseña del usuario \"{user}\" para autorizar modificaciones " +"en la cuenta." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Contraseña no válida." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Ha fallado la creación de usuaria/o LDAP: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Ha fallado añadir usuaria/o nuevo al grupo {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Claves de SSH autorizadas" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7821,36 +7821,36 @@ msgstr "" "de una clave. Puede introducir más de una clave, cada una en una línea. Las " "líneas en blanco y las que empiecen por # se ignorarán." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Ha fallado renombrar al o la usuaria LDAP." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Ha fallado la eliminación del o de la usuaria del grupo." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Ha fallado añadir al o la usuaria al grupo." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "No es posible configurar las claves SSH." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Ha fallado al cambiar el estado del usuario." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Ha fallado cambiar la clave del o de la usuaria LDAP." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Ha fallado añadir usuaria/o nueva/o al grupo admin: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Creada cuenta de usuaria/o, ya está usted en el sistema" @@ -8391,7 +8391,7 @@ msgstr "" "WordPress o blog a los administradores. Habilítalo solo después de ejecutar " "la configuración inicial de WordPress." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8413,7 +8413,7 @@ msgstr "" "de mapa y calendario. Se pueden compartir fotos sueltas con otras personas " "enviándoles un enlace directo." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8424,11 +8424,11 @@ msgstr "" "Para añadir más usuarios hay que crear cuentas con el mismo nombre tanto en " "Zoph como en {box_name} ." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Organizador de fotografías" @@ -8486,87 +8486,87 @@ msgid "Package {package_expression} is not available for install" msgstr "" "El paquete {package_expression} no está disponible para su instalación." -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "El paquete {package_name} es la última versión ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "instalando" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "descargando" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "cambio de medio" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "archivo de configuración: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Tiempo máximo esperando al administrador de paquetes" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Instalando app" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Actualizando app" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Error al instalar la app: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Error al actualizar la aplicación: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Error al instalar la app: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Error al actualizar la app: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "App instalada." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "App actualizada" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Instalando app" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Error al desinstalar la aplicación: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Error desinstalando la aplicación: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Aplicación desinstalada." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Actualizando los paquetes de la app" @@ -8959,11 +8959,11 @@ msgstr "" "Todos los datos de la aplicación y la configuración se perderán " "permanentemente. La aplicación se puede instalar de nuevo." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Configuración sin cambio" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "antes de desinstalar {app_id}" diff --git a/plinth/locale/fa/LC_MESSAGES/django.po b/plinth/locale/fa/LC_MESSAGES/django.po index 9ff2da9d9..17bc00f30 100644 --- a/plinth/locale/fa/LC_MESSAGES/django.po +++ b/plinth/locale/fa/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Persian http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6824,7 +6824,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6975,7 +6975,7 @@ msgstr "پیکربندی فعلی شبکه" msgid "Error configuring app: {error}" msgstr "خطا هنگام نصب برنامه: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6984,20 +6984,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -7352,14 +7352,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "برنامه نصب شد." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7367,25 +7367,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7394,36 +7394,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid server name" -msgid "Enter a valid username." -msgstr "نام کاربری معتبر نیست" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Account" -msgid "Authorization Password" -msgstr "حساب مدیر" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -#, fuzzy -#| msgid "Show password" -msgid "Invalid password." -msgstr "رمز را نشان بده" - -#: modules/users/forms.py:112 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 " @@ -7432,62 +7403,91 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid server name" +msgid "Enter a valid username." +msgstr "نام کاربری معتبر نیست" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +#, fuzzy +#| msgid "Administrator Account" +msgid "Authorization Password" +msgstr "حساب مدیر" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Show password" +msgid "Invalid password." +msgstr "رمز را نشان بده" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "ساختن کاربر LDAP شکست خورد." -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to {group} group: {error}" msgstr "افزودن کاربر به گروه مدیران شکست خورد." -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 #, fuzzy #| msgid "Failed to add new user to admin group." msgid "Failed to change user status." msgstr "افزودن کاربر به گروه مدیران شکست خورد." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "افزودن کاربر به گروه مدیران شکست خورد." -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "حساب کاربری ساخته شد، شما الان وارد سیستم هستید" @@ -8023,7 +8023,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8036,7 +8036,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8044,11 +8044,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -8105,96 +8105,96 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format msgid "Error installing app: {string} {details}" msgstr "خطا هنگام نصب برنامه: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format msgid "Error updating app: {string} {details}" msgstr "خطا هنگام نصب برنامه: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "خطا هنگام نصب برنامه: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "خطا هنگام نصب برنامه: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy msgid "App installed." msgstr "برنامه نصب شد." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "آخرین به‌روزرسانی" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "خطا هنگام نصب برنامه: {error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "خطا هنگام نصب برنامه: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "خطا هنگام نصب برنامه: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy msgid "App uninstalled." msgstr "برنامه نصب شد." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8563,11 +8563,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/fake/LC_MESSAGES/django.po b/plinth/locale/fake/LC_MESSAGES/django.po index 4cb919466..36b131d07 100644 --- a/plinth/locale/fake/LC_MESSAGES/django.po +++ b/plinth/locale/fake/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Plinth 0.6\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2016-01-31 22:24+0530\n" "Last-Translator: Sunil Mohan Adapa \n" "Language-Team: Plinth Developers HTTP://CONFIG.PRIVOXY.ORG/ OR HTTP://P.P.\"" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 #, fuzzy #| msgid "Enable Privoxy" msgid "Privoxy" msgstr "ENABLE PRIVOXY" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 #, fuzzy #| msgid "Privoxy Web Proxy" msgid "Web Proxy" msgstr "PRIVOXY WEB PROXY" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "ACCESS {url} WITH PROXY {proxy} ON TCP{kind}" @@ -7197,7 +7197,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 #, fuzzy #| msgid "" #| "Tor is an anonymous communication system. You can learn more about it " @@ -7373,7 +7373,7 @@ msgstr "AN ERROR OCCURRED DURING CONFIGURATION." msgid "Error configuring app: {error}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7382,22 +7382,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "Privoxy Web Proxy" msgid "Tor Proxy" msgstr "PRIVOXY WEB PROXY" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "ACCESS URL {url} ON TCP{kind} VIA TOR" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "CONFIRM TOR USAGE AT {url} ON TCP{kind}" @@ -7806,14 +7806,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "AUTOMATIC UPGRADES ENABLED" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7821,25 +7821,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "USERS AND GROUPS" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "CHECK LDAP ENTRY \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7848,37 +7848,8 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid server name" -msgid "Enter a valid username." -msgstr "INVALID SERVER NAME" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Account" -msgid "Authorization Password" -msgstr "ADMINISTRATOR ACCOUNT" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 #, fuzzy -#| msgid "Show password" -msgid "Invalid password." -msgstr "SHOW PASSWORD" - -#: modules/users/forms.py:112 -#, 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, " @@ -7898,23 +7869,52 @@ msgstr "" "ABLE TO LOG IN TO ALL SERVICES. THEY CAN ALSO LOG IN TO THE SYSTEM THROUGH " "SSH AND HAVE ADMINISTRATIVE PRIVILEGES (SUDO)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid server name" +msgid "Enter a valid username." +msgstr "INVALID SERVER NAME" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +#, fuzzy +#| msgid "Administrator Account" +msgid "Authorization Password" +msgstr "ADMINISTRATOR ACCOUNT" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Show password" +msgid "Invalid password." +msgstr "SHOW PASSWORD" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "CREATING LDAP USER FAILED." -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" msgstr "FAILED TO ADD NEW USER TO {group} GROUP." -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7924,39 +7924,39 @@ msgstr "" "SYSTEM WITHOUT USING A PASSWORD. YOU MAY ENTER MULTIPLE KEYS, ONE ON EACH " "LINE. BLANK LINES AND LINES STARTING WITH # WILL BE IGNORED." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "RENAMING LDAP USER FAILED." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "FAILED TO REMOVE USER FROM GROUP." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "FAILED TO ADD USER TO GROUP." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "FAILED TO ADD USER TO GROUP." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "CHANGING LDAP USER PASSWORD FAILED." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "FAILED TO ADD NEW USER TO ADMIN GROUP." -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "USER ACCOUNT CREATED, YOU ARE NOW LOGGED IN" @@ -8505,7 +8505,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8518,7 +8518,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8526,11 +8526,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -8588,108 +8588,108 @@ msgstr "SERVICE DISABLED: {name}" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 #, fuzzy #| msgid "Installation" msgid "installing" msgstr "INSTALLATION" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 #, fuzzy #| msgid "Setting unchanged" msgid "media change" msgstr "SETTING UNCHANGED" -#: package.py:388 +#: package.py:391 #, fuzzy, python-brace-format #| msgid "Configuration" msgid "configuration file: {file}" msgstr "CONFIGURATION" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install" msgid "Installing app" msgstr "INSTALL" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error installing app: {error}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error updating app: {error}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Applications" msgid "App installed." msgstr "APPLICATIONS" -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "LAST UPDATE" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install" msgid "Uninstalling app" msgstr "INSTALL" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing packages: {string} {details}" msgid "Error uninstalling app: {error}" msgstr "ERROR INSTALLING PACKAGES: {string} {details}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Applications" msgid "App uninstalled." msgstr "APPLICATIONS" -#: setup.py:453 +#: setup.py:513 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -9099,11 +9099,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "SETTING UNCHANGED" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/fr/LC_MESSAGES/django.po b/plinth/locale/fr/LC_MESSAGES/django.po index cc10cbda3..6653a5a86 100644 --- a/plinth/locale/fr/LC_MESSAGES/django.po +++ b/plinth/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-01-05 07:09+0000\n" "Last-Translator: John Doe \n" "Language-Team: French http://config.privoxy.org/ ou http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Serveur mandataire web" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Accéder à l’URL {url} avec le mandataire {proxy} sur tcp{kind}" @@ -7258,7 +7258,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Synchronisation de fichiers" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7431,7 +7431,7 @@ msgstr "Mise à jour de la configuration" msgid "Error configuring app: {error}" msgstr "Erreur lors de la configuration de l’application : {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7445,20 +7445,20 @@ msgstr "" "Internet par le réseau Tor. La censure des FAI peut être contourné en " "utilisant des ponts en amont (upstream bridges)." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Mandataire Tor" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Mandataire Socks Tor" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Accédez à l’URL {url} sur tcp{kind} via Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Confirmez l’utilisation de Tor pour {url} sur tcp{kind}" @@ -7874,7 +7874,7 @@ msgstr "Mise à jour régulière des fonctionnalités activée." msgid "Starting distribution upgrade test." msgstr "Démarrage du test de mise à niveau de la distribution." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7885,7 +7885,7 @@ msgstr "" "Certaines applis demandent en outre que les comptes soient membres d’un " "groupe particulier pour pouvoir accéder à l’application." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7897,25 +7897,25 @@ msgstr "" "principale. En revanche, seuls les utilisateurs membres du groupe admin peuvent modifier les applications ou changer les paramètres système." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Utilisateurs et groupes" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Accès à tous les services et à la configuration du système" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Vérification de l’entrée LDAP « {search_item} »" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Vérifier la configuration nslcd \"{key} {value}\"" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Vérifier la configuration nsswitch \"{database}\"" @@ -7924,34 +7924,7 @@ msgstr "Vérifier la configuration nsswitch \"{database}\"" msgid "Username is taken or is reserved." msgstr "Le nom d’utilisateur est déjà pris ou est réservé." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Entrez un nom d’utilisateur valide." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Requis. 150 caractères ou moins. Lettres anglaises, chiffres et @/./-/_ " -"uniquement." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Mot de passe actuel" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Veuillez saisir votre mot de passe de l’utilisateur « {user} » pour " -"confirmer ces modifications de compte." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Mot de passe incorrect." - -#: modules/users/forms.py:112 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 " @@ -7966,21 +7939,48 @@ msgstr "" "peuvent également se connecter au système avec Secure Shell (SSH) et obtenir " "les privilèges d’administrateur (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Entrez un nom d’utilisateur valide." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Requis. 150 caractères ou moins. Lettres anglaises, chiffres et @/./-/_ " +"uniquement." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Mot de passe actuel" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Veuillez saisir votre mot de passe de l’utilisateur « {user} » pour " +"confirmer ces modifications de compte." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Mot de passe incorrect." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "La création de l’utilisateur LDAP a échoué : {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "L’ajout du nouvel utilisateur au groupe {group} a échoué : {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Clés SSH autorisées" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7991,36 +7991,36 @@ msgstr "" "plusieurs clefs, une sur chaque ligne. Les lignes vides et celles commençant " "par # sont ignorées." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Le changement du nom de l’utilisateur LDAP a échoué." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Échec du retrait de l’utilisateur du groupe." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Échec de l’ajout de l’utilisateur au groupe." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Échec du paramétrage des clefs SSH." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Échec du changement de statut de l’utilisateur." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Le changement du mot de passe de l’utilisateur LDAP a échoué." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "L’ajout du nouvel utilisateur au groupe admin a échoué : {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Compte utilisateur créé, vous êtes maintenant connecté" @@ -8572,7 +8572,7 @@ msgstr "" "WordPress. N’activez cette option qu’après avoir réalisé la configuration " "initiale de WordPress." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8595,7 +8595,7 @@ msgstr "" "recherche, de carte et de calendrier. Les photos peuvent être partagées " "unitairement avec d’autres en leur envoyant un lien direct." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8606,11 +8606,11 @@ msgstr "" "l’administrateur Zoph. Pour ajouter des utilisateurs ceux-ci doivent être " "créés à la fois sur la {box_name} et dans Zoph avec le même identifiant." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Photothèque" @@ -8670,87 +8670,87 @@ msgstr "Terminé : {name}" msgid "Package {package_expression} is not available for install" msgstr "Le paquet {expression} n’est pas disponible à l’installation" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Le paquet {package_name} est à la dernière version ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "installation en cours" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "téléchargement en cours" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "changement de support" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "fichier de configuration : {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Aucune réponse du gestionnaire de paquets" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Installation de l’application" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Mise à jour de l’application" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Erreur lors de l’installation de l’appli : {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Erreur lors de la mise à jour de l’appli : {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Erreur lors de l’installation de l’appli : {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Erreur lors de la mise à jour de l’appli : {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "Application installée." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Application mise à jour" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Désinstallation de l’application" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Erreur lors de la désinstallation de l’appli : {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Erreur lors de la désinstallation de l’appli : {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Application désinstallée." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Mise à jour des paquets de l’application" @@ -9149,11 +9149,11 @@ msgstr "" "L’ensemble données de l’appli et sa configuration seront définitivement " "perdus. Un appli peut toujours être réinstallée de zéro." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Paramètre inchangé" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "avant la désinstallation de {app_id}" diff --git a/plinth/locale/gl/LC_MESSAGES/django.po b/plinth/locale/gl/LC_MESSAGES/django.po index 2a924b202..b215b588b 100644 --- a/plinth/locale/gl/LC_MESSAGES/django.po +++ b/plinth/locale/gl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-12-30 10:51+0000\n" "Last-Translator: gallegonovato \n" "Language-Team: Galician http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6186,7 +6186,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6329,7 +6329,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6338,20 +6338,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6695,14 +6695,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6710,25 +6710,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6737,30 +6737,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6769,57 +6746,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7303,7 +7303,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7316,7 +7316,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7324,11 +7324,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7383,99 +7383,99 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Produciuse un erro ao instalar o aplicativo: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Produciuse un erro ao instalar o aplicativo: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplicativo instalado." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Produciuse un erro ao instalar o aplicativo: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Produciuse un erro ao instalar o aplicativo: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplicativo instalado." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7832,11 +7832,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/gu/LC_MESSAGES/django.po b/plinth/locale/gu/LC_MESSAGES/django.po index 6115ff499..bfd393a83 100644 --- a/plinth/locale/gu/LC_MESSAGES/django.po +++ b/plinth/locale/gu/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2021-01-18 12:32+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Gujarati http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6480,7 +6480,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6631,7 +6631,7 @@ msgstr "સામાન્ય ગોઠવણી" msgid "Error configuring app: {error}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6640,20 +6640,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -7021,14 +7021,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "વપરાશકર્તા રજીસ્ટ્રેશન અક્ષમ છે" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7036,25 +7036,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7063,34 +7063,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid server name" -msgid "Enter a valid username." -msgstr "અમાન્ય સર્વર નામ" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -#, fuzzy -#| msgid "Show password" -msgid "Invalid password." -msgstr "પાસવર્ડ બતાવો" - -#: modules/users/forms.py:112 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 " @@ -7099,57 +7072,84 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid server name" +msgid "Enter a valid username." +msgstr "અમાન્ય સર્વર નામ" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Show password" +msgid "Invalid password." +msgstr "પાસવર્ડ બતાવો" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7655,7 +7655,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7668,7 +7668,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7676,11 +7676,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7737,103 +7737,103 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "એપ્લિકેશન્સ ઇન્સ્ટોલ કરો" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {string}{details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {string}{details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "એપ્લીકેશન પ્રસ્થાપિત થઇ ગઈ છે." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "છેલ્લો સુધારો" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "એપ્લિકેશન્સ ઇન્સ્ટોલ કરો" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {string}{details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "એપ્લીકેશન પ્રસ્થાપિત કરતાં ભૂલ થઇ છે: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "એપ્લીકેશન પ્રસ્થાપિત થઇ ગઈ છે." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8205,11 +8205,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "સેટિંગ યથાવત" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/hi/LC_MESSAGES/django.po b/plinth/locale/hi/LC_MESSAGES/django.po index 5900c1ba4..87384d93b 100644 --- a/plinth/locale/hi/LC_MESSAGES/django.po +++ b/plinth/locale/hi/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2023-10-19 06:30+0000\n" "Last-Translator: Shaik \n" "Language-Team: Hindi %(service_name)s is running." msgid "Service {service_name} is running" msgstr "सर्विस %(service_name)s चल रहा है." -#: daemon.py:164 +#: daemon.py:218 #, python-brace-format msgid "Listening on {kind} port {listen_address}:{port}" msgstr "{kind} में सुन कर पोर्ट {listen_address} :{port}" -#: daemon.py:167 +#: daemon.py:221 #, python-brace-format msgid "Listening on {kind} port {port}" msgstr "{kind} में सुन कर पोर्ट{port}" -#: daemon.py:236 +#: daemon.py:291 #, python-brace-format msgid "Connect to {host}:{port}" msgstr "{host}:{port} से जुड़े" -#: daemon.py:240 +#: daemon.py:299 #, python-brace-format msgid "Cannot connect to {host}:{port}" msgstr "{host}:{port} से नहीं जोड़ सखता" @@ -122,12 +122,12 @@ msgstr "वेब सर्वर" msgid "{box_name} Web Interface (Plinth)" msgstr "{box_name} वेब इंटरफेस (प्लिंथ)" -#: modules/apache/components.py:154 +#: modules/apache/components.py:159 #, python-brace-format msgid "Access URL {url} on tcp{kind}" msgstr "इस यूआरएल का अपयोग करें {url} टीसीपी पर {kind}" -#: modules/apache/components.py:157 +#: modules/apache/components.py:162 #, python-brace-format msgid "Access URL {url}" msgstr "इस यूआरएल का अपयोग करें {url}" @@ -840,7 +840,7 @@ msgid "Permissions for anonymous users, who have not provided a password." msgstr "" #: modules/bepasty/forms.py:27 modules/bepasty/templates/bepasty.html:30 -#: modules/users/forms.py:110 modules/users/forms.py:233 +#: modules/users/forms.py:91 msgid "Permissions" msgstr "अनुमतियाँ" @@ -1505,7 +1505,7 @@ msgstr "डायरेक्टरी डाउनलोड करें" msgid "Bittorrent client written in Python/PyGTK" msgstr "बिटटोरेंट ग्राहक पाईथोन/पाईजिटिके" -#: modules/diagnostics/__init__.py:27 +#: modules/diagnostics/__init__.py:28 msgid "" "The system diagnostic test will run a number of checks on your system to " "confirm that applications and services are working as expected." @@ -1513,79 +1513,79 @@ msgstr "" "पुष्टि करने के लिये कि एप्लिकेशन या सेवाएं अच्छेसे चल रहे है, सिस्टम निदान परिक्षा बहुत सारे " "चेकों करोगे." -#: modules/diagnostics/__init__.py:51 modules/diagnostics/__init__.py:236 +#: modules/diagnostics/__init__.py:52 modules/diagnostics/__init__.py:238 msgid "Diagnostics" msgstr "निदानिकी" -#: modules/diagnostics/__init__.py:95 +#: modules/diagnostics/__init__.py:96 #, fuzzy #| msgid "Quassel" msgid "passed" msgstr "क्वासेल" -#: modules/diagnostics/__init__.py:96 modules/networks/views.py:50 +#: modules/diagnostics/__init__.py:97 modules/networks/views.py:50 #, fuzzy #| msgid "Setup failed." msgid "failed" msgstr "सेटअप विफल." -#: modules/diagnostics/__init__.py:97 +#: modules/diagnostics/__init__.py:98 msgid "error" msgstr "" -#: modules/diagnostics/__init__.py:98 +#: modules/diagnostics/__init__.py:99 msgid "warning" msgstr "" #. Translators: This is the unit of computer storage Mebibyte similar to #. Megabyte. -#: modules/diagnostics/__init__.py:202 +#: modules/diagnostics/__init__.py:204 msgid "MiB" msgstr "" #. Translators: This is the unit of computer storage Gibibyte similar to #. Gigabyte. -#: modules/diagnostics/__init__.py:207 +#: modules/diagnostics/__init__.py:209 msgid "GiB" msgstr "" -#: modules/diagnostics/__init__.py:214 +#: modules/diagnostics/__init__.py:216 msgid "You should disable some apps to reduce memory usage." msgstr "" -#: modules/diagnostics/__init__.py:219 +#: modules/diagnostics/__init__.py:221 msgid "You should not install any new apps on this system." msgstr "" -#: modules/diagnostics/__init__.py:231 +#: modules/diagnostics/__init__.py:233 #, no-python-format, python-brace-format msgid "" "System is low on memory: {percent_used}% used, {memory_available} " "{memory_available_unit} free. {advice_message}" msgstr "" -#: modules/diagnostics/__init__.py:233 +#: modules/diagnostics/__init__.py:235 msgid "Low Memory" msgstr "" -#: modules/diagnostics/__init__.py:264 +#: modules/diagnostics/__init__.py:266 #, fuzzy #| msgid "Run Diagnostics" msgid "Running diagnostics" msgstr "निदानिकी चलिये" -#: modules/diagnostics/__init__.py:307 +#: modules/diagnostics/__init__.py:309 #, no-python-format, python-brace-format msgid "Found {issue_count} issues during routine tests." msgstr "" -#: modules/diagnostics/__init__.py:308 +#: modules/diagnostics/__init__.py:310 #, fuzzy #| msgid "Diagnostic Results" msgid "Diagnostics results" msgstr "निदानिकी का परिणाम" -#: modules/diagnostics/__init__.py:313 +#: modules/diagnostics/__init__.py:315 #, fuzzy #| msgid "Diagnostic Results" msgid "Go to diagnostics results" @@ -1677,7 +1677,7 @@ msgstr "परीक्षा" msgid "Result" msgstr "परिणाम" -#: modules/diagnostics/views.py:107 +#: modules/diagnostics/views.py:111 msgid "Diagnostic Test" msgstr "निदान परिक्षा" @@ -1843,7 +1843,7 @@ msgid "Use HTTP basic authentication" msgstr "एचटिटिपि बेसिकॅ प्रमाणीकरण उपयोग करें" #: modules/dynamicdns/forms.py:88 modules/networks/forms.py:207 -#: modules/users/forms.py:67 +#: modules/users/forms.py:117 msgid "Username" msgstr "युसरनाम" @@ -2269,33 +2269,33 @@ msgstr "" msgid "Firewall" msgstr "फ़ायरवॉल" -#: modules/firewall/__init__.py:271 +#: modules/firewall/__init__.py:272 #, fuzzy #| msgid "Default app set" msgid "Default zone is external" msgstr "डिफ़ॉल्ट एेप सेट" -#: modules/firewall/__init__.py:280 +#: modules/firewall/__init__.py:282 msgid "Firewall backend is nftables" msgstr "" -#: modules/firewall/__init__.py:293 +#: modules/firewall/__init__.py:296 msgid "Direct passthrough rules exist" msgstr "" -#: modules/firewall/components.py:136 +#: modules/firewall/components.py:139 #, fuzzy, python-brace-format #| msgid "%(service_name)s is available only on internal networks." msgid "Port {name} ({details}) available for internal networks" msgstr "%(service_name)s सिर्फ आंतरिक नेटवर्क्स पर उपलब्ध है." -#: modules/firewall/components.py:147 +#: modules/firewall/components.py:153 #, fuzzy, python-brace-format #| msgid "%(service_name)s is available only on internal networks." msgid "Port {name} ({details}) available for external networks" msgstr "%(service_name)s सिर्फ आंतरिक नेटवर्क्स पर उपलब्ध है." -#: modules/firewall/components.py:153 +#: modules/firewall/components.py:159 #, python-brace-format msgid "Port {name} ({details}) unavailable for external networks" msgstr "" @@ -2422,11 +2422,11 @@ msgstr "" msgid "Read-write access to Git repositories" msgstr "" -#: modules/gitweb/__init__.py:50 modules/gitweb/manifest.py:11 +#: modules/gitweb/__init__.py:48 modules/gitweb/manifest.py:11 msgid "Gitweb" msgstr "" -#: modules/gitweb/__init__.py:51 +#: modules/gitweb/__init__.py:49 msgid "Simple Git Hosting" msgstr "" @@ -2944,7 +2944,7 @@ msgid "I2P" msgstr "" #: modules/i2p/__init__.py:53 modules/tor/__init__.py:63 -#: modules/torproxy/__init__.py:56 +#: modules/torproxy/__init__.py:57 msgid "Anonymity Network" msgstr "गुमनामी नेटवर्क" @@ -4054,19 +4054,19 @@ msgstr "सुरक्षित शेल" msgid "Services" msgstr "सर्विस" -#: modules/networks/__init__.py:35 +#: modules/networks/__init__.py:36 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: modules/networks/__init__.py:37 +#: modules/networks/__init__.py:38 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: modules/networks/__init__.py:58 +#: modules/networks/__init__.py:59 msgid "Networks" msgstr "नेटवर्क्‍स" @@ -5592,7 +5592,7 @@ msgid "" "network for additional anonymity if Tor app is enabled." msgstr "" -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5602,7 +5602,7 @@ msgstr "" "लिए, वेब पेज डेटा और HTTP हेडर को मोडिफाई करने के लिए, ऐकसेस को नियंत्रित करने के लिए " "और एड या दुसरा इंटरनेट का जंक हटाने के लिए. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, fuzzy, python-brace-format #| msgid "" #| "You can use Privoxy by modifying your browser proxy settings to your " @@ -5624,15 +5624,15 @@ msgstr "" "org\">http://config.privoxy.org/ या http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "प्रिवोक्सी" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "वेब प्रॉक्सी" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "{url} ऐकसेस करें प्रॉक्सी लेकर {proxy} टीसीपी पर{kind}" @@ -7134,7 +7134,7 @@ msgstr "सिंकतिन्ग" msgid "File Synchronization" msgstr "फ़ाइल सिंक्रनाइज़ेशन" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7310,7 +7310,7 @@ msgstr "कॉंफ़िगरेशन के दौरान कूछ त msgid "Error configuring app: {error}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7319,22 +7319,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "Tor Socks Proxy" msgid "Tor Proxy" msgstr "टोर सोक्स प्रॉक्सी" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "टोर सोक्स प्रॉक्सी" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "यूआरएल एक्सेस करें {url} टीसीपी पर {kind} टोर के माध्यम से" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "टोर उपयोग की पुष्टि करें {url} पर टीसीपी पर {kind}" @@ -7757,14 +7757,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "ऑटोमेटिक अपग्रेडस सक्षम किया गया" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7772,25 +7772,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "यूसरस और समूह" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "सब सर्विसस और सिस्टम सेटिंग्स तक पहुंच" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "एलडीएपी प्रविष्टि चेक करें \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7799,37 +7799,8 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "यूसरनाम लिया है या आरक्षित है." -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid server name" -msgid "Enter a valid username." -msgstr "सर्वर नाम अमान्य है" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Password" -msgid "Authorization Password" -msgstr "व्यवस्थापक पासवर्ड" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 #, fuzzy -#| msgid "Show password" -msgid "Invalid password." -msgstr "शो पासवर्ड" - -#: modules/users/forms.py:112 -#, 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, " @@ -7848,23 +7819,52 @@ msgstr "" "

एडमिन ग्रुप के यूसरस सब सर्विसस पर लॉग इन कर सकेगें. SSH के माध्यम से भी " "सिस्टम पर लॉग इन कर सकते है अाैर उनको प्रशासनिक विशेषाधिकार (sudo) है." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid server name" +msgid "Enter a valid username." +msgstr "सर्वर नाम अमान्य है" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +#, fuzzy +#| msgid "Administrator Password" +msgid "Authorization Password" +msgstr "व्यवस्थापक पासवर्ड" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Show password" +msgid "Invalid password." +msgstr "शो पासवर्ड" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, fuzzy, python-brace-format #| msgid "Creating LDAP user failed." msgid "Creating LDAP user failed: {error}" msgstr "एलडीएपी यूसर बनाना विफल रहा." -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, fuzzy, python-brace-format #| msgid "Failed to add new user to {group} group." msgid "Failed to add new user to {group} group: {error}" msgstr "{group} समूह में नया यूसर जोड़ने में विफल." -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7874,39 +7874,39 @@ msgstr "" "बिना सिस्टम में प्रवेश करने की अनुमति देगा. आप एकाधिक कीज़ दर्ज कर सकते हैं, हर लाइन रक " "एक. खाली लाइनस या # से प्रारंभ होने वाले लाइनस अनदेखा कर दिया जाएगा." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "एलडीएपी यूसर का नाम बदलना विफल रहा." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "समूह से यूसर को हटाने में विफल." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "समूह से यूसर को जोड़ने में विफल." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "एसएसएच कीज़ सेट करने में असमर्थ." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "समूह से यूसर को जोड़ने में विफल." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "एलडीएपी यूसर का पासवर्ड बदलना विफल रहा." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, fuzzy, python-brace-format #| msgid "Failed to add new user to admin group." msgid "Failed to add new user to admin group: {error}" msgstr "व्यवस्थापक समूह में नया यूसर जोड़ने में विफल." -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "युसर अकाउंट बनाया, अब आप लॉगड इन हैं" @@ -8463,7 +8463,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8476,7 +8476,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8484,11 +8484,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -8546,103 +8546,103 @@ msgstr "सर्विस सक्षम किया गया:{name}" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "इंस्टॉलिंग" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "डाउनलोडिंग" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "मीडिया बदलाव" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "कॉंफ़िगरेशन फ़ाइल: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "ऐप्लिकेशन इंस्टॉल करें" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता : {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता : {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "एप्लिकेशन इंस्टॉल हो गया." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "अंतिम अपडेट" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "ऐप्लिकेशन इंस्टॉल करें" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता : {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "एप्लिकेशन नहीं इंस्टॉल जा सकता: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "एप्लिकेशन इंस्टॉल हो गया." -#: setup.py:453 +#: setup.py:513 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -9042,11 +9042,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "सेटिंग स्थिर है" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/hu/LC_MESSAGES/django.po b/plinth/locale/hu/LC_MESSAGES/django.po index 29fd8c3fc..512d94346 100644 --- a/plinth/locale/hu/LC_MESSAGES/django.po +++ b/plinth/locale/hu/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-10-24 18:39+0000\n" "Last-Translator: Sunil Mohan Adapa \n" "Language-Team: Hungarian http://config.privoxy.org/ és http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Web proxy" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -7186,7 +7186,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Fájlszinkronizáció" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7361,7 +7361,7 @@ msgstr "Beállítások frissítése" msgid "Error configuring app: {error}" msgstr "Hiba lépett fel az alkalmazás konfigurációja során: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7370,22 +7370,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "Tor Socks Proxy" msgid "Tor Proxy" msgstr "Tor Socks proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor Socks proxy" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Hozzáférés a {url} URL-hez tcp{kind}-on Tor használatával" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Hagyd jóvá a Tor használatát {url} célcímhez tcp{kind} protokollon" @@ -7795,7 +7795,7 @@ msgstr "Gyakori funkciófrissítések aktiválva." msgid "Starting distribution upgrade test." msgstr "Disztribúció frissítés engedélyezve" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7806,7 +7806,7 @@ msgstr "" "alkalmazások megkövetelik továbbá, hogy a felhasználói fiók egy csoport " "tagja legyen, hogy a felhasználó hozzáférhessen az alkalmazáshoz." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7818,25 +7818,25 @@ msgstr "" "az admin csoport felhasználói módosíthatják az alkalmazásokat vagy " "a rendszerbeállításokat." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Felhasználók és csoportok" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Hozzáférés az összes szolgáltatáshoz és rendszerbeállításhoz" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP-bejegyzés ellenőrzése: \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7845,32 +7845,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "A felhasználónév foglalt." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Adj meg egy érvényes felhasználónevet." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Szükséges. Legfeljebb 150 karakter. Csak angol betűk, számjegyek és @/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Hitelesítési jelszó" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"A fiókmódosítások engedélyezéséhez add meg \"{user}\" felhasználó jelszavát." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Érvénytelen jelszó." - -#: modules/users/forms.py:112 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 " @@ -7886,22 +7861,47 @@ msgstr "" "képesek bejelentkezni a rendszerbe, ahol adminisztrátori jogosultságokkal " "rendelkeznek (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Adj meg egy érvényes felhasználónevet." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Szükséges. Legfeljebb 150 karakter. Csak angol betűk, számjegyek és @/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Hitelesítési jelszó" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"A fiókmódosítások engedélyezéséhez add meg \"{user}\" felhasználó jelszavát." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Érvénytelen jelszó." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "LDAP-felhasználó létrehozása sikertelen: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" "Az új felhasználó hozzáadása a(z) {group} csoporthoz nem sikerült: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Engedélyezett SSH-kulcsok" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7911,38 +7911,38 @@ msgstr "" "jelszó nélkül jelentkezzen be. Több kulcs is megadható; soronként egy. Az " "üres, illetve # jellel kezdődő sorok nem számítanak." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "LDAP-felhasználó átnevezése sikertelen." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Nem sikerült eltávolítani a felhasználót a csoportból." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Nem sikerült hozzáadni a felhasználót a csoporthoz." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "SSH-kulcsok beállítása sikertelen." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Nem sikerült a felhasználói állapot megváltoztatása." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "LDAP-felhasználó jelszavának megváltoztatása sikertelen." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Nem sikerült hozzáadni az új felhasználót a rendszergazdai csoporthoz: " "{error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Felhasználói fiók létrehozva, bejelentkezés sikeres" @@ -8489,7 +8489,7 @@ msgstr "" "teszi lehetővé a WordPress webhely vagy blog megtekintését. Csak a WordPress " "kezdeti beállításának elvégzése után engedélyezd." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8511,7 +8511,7 @@ msgstr "" "tartózkodási hely alapján. Az egyes fényképek közvetlen link elküldésével " "megoszthatók másokkal." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8523,11 +8523,11 @@ msgstr "" "rendszerben is létre kell hozni egy-egy fiókot ugyanazzal a " "felhasználónévvel." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Fotó szervező" @@ -8587,105 +8587,105 @@ msgstr "Szolgáltatás letiltva: {name}" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "A(z) {package_name} a legfrissebb verzió ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "telepítés" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "letöltés" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "adathordozó csere" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "konfigurációs fájl: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Alkalmazások telepítése" -#: setup.py:43 +#: setup.py:41 #, fuzzy #| msgid "Updating..." msgid "Updating app" msgstr "Frissítés…" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Alkalmazás telepítve." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Legutolsó frissítés" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Alkalmazások telepítése" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Hiba lépett fel az alkalmazás telepítésekor: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Alkalmazás telepítve." -#: setup.py:453 +#: setup.py:513 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -9086,11 +9086,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "A beállítás változatlan" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/id/LC_MESSAGES/django.po b/plinth/locale/id/LC_MESSAGES/django.po index 7d8a73b58..f1406cfcd 100644 --- a/plinth/locale/id/LC_MESSAGES/django.po +++ b/plinth/locale/id/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Indonesian (FreedomBox)\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Indonesian http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Proksi Web" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Akses {url} dengan proksi {proxy} pada tcp{kind}" @@ -6675,7 +6675,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6826,7 +6826,7 @@ msgstr "Terjadi kesalahan selama konfigurasi." msgid "Error configuring app: {error}" msgstr "Kesalahan pemasangan aplikasi: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6835,22 +6835,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2p proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -7221,14 +7221,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "Pembaruan distribusi dinonaktifkan" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7236,25 +7236,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7263,32 +7263,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Masukkan sebuah nama pengguna yang valid." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Account" -msgid "Authorization Password" -msgstr "Akun Administrator" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Kata sandi tidak valid." - -#: modules/users/forms.py:112 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 " @@ -7297,59 +7272,84 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Masukkan sebuah nama pengguna yang valid." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +#, fuzzy +#| msgid "Administrator Account" +msgid "Authorization Password" +msgstr "Akun Administrator" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Kata sandi tidak valid." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Gagal membuat pengguna LDAP. {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Gagal menambahkan pengguna baru ke kelompok {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 #, fuzzy #| msgid "Failed to add new user to admin group." msgid "Failed to change user status." msgstr "Gagal menambahkan pengguna baru ke kelompok admin." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Gagal menambahkan pengguna baru ke kelompok admin. {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7857,7 +7857,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7870,7 +7870,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7878,11 +7878,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7937,103 +7937,103 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "memasang" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "mengunduh" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Instal aplikasi" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Kesalahan Pemasangan aplikasi: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Kesalahan Pemasangan aplikasi: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Kesalahan pemasangan aplikasi: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Kesalahan pemasangan aplikasi: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikasi telah terpasang." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Pembaharuan Terakhir" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Instal aplikasi" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Kesalahan Pemasangan aplikasi: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Kesalahan pemasangan aplikasi: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikasi telah terpasang." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8402,11 +8402,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/it/LC_MESSAGES/django.po b/plinth/locale/it/LC_MESSAGES/django.po index 304ae774d..438e007a9 100644 --- a/plinth/locale/it/LC_MESSAGES/django.po +++ b/plinth/locale/it/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Italian http://config." "Privoxy.org/ o http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Web Proxy" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Accesso {url} con proxy {proxy} su tcp{kind}" @@ -6809,7 +6809,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6956,7 +6956,7 @@ msgstr "Aggiornamento della configurazione" msgid "Error configuring app: {error}" msgstr "Errore durante l'installazione dell'applicazione: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6965,22 +6965,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "Proxy I2P" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -7333,14 +7333,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7348,25 +7348,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7375,30 +7375,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Inserisci un nome utente valido." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Password di autorizzazione" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Password non valida." - -#: modules/users/forms.py:112 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 " @@ -7407,57 +7384,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Inserisci un nome utente valido." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Password di autorizzazione" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Password non valida." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Fallito l'inserimento di un nuovo utente nel gruppo {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Aggiunta del nuovo utente al gruppo admin fallita: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7939,7 +7939,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7952,7 +7952,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7960,11 +7960,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -8020,103 +8020,103 @@ msgstr "Servizio disabilitato: {name}" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Installa App" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Errore installazione applicazione: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Errore installazione applicazione: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Errore durante l'installazione dell'applicazione: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Errore durante l'installazione dell'applicazione: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Applicazione installata." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Ultimo aggiornamento" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Installa App" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Errore installazione applicazione: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Errore durante l'installazione dell'applicazione: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Applicazione installata." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8481,11 +8481,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Impostazioni invariate" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/ja/LC_MESSAGES/django.po b/plinth/locale/ja/LC_MESSAGES/django.po index bc87e0872..7612732a8 100644 --- a/plinth/locale/ja/LC_MESSAGES/django.po +++ b/plinth/locale/ja/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2023-05-07 23:50+0000\n" "Last-Translator: Nobuhiro Iwamatsu \n" "Language-Team: Japanese http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6164,7 +6164,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6306,7 +6306,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6315,20 +6315,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6666,14 +6666,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6681,25 +6681,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6708,30 +6708,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6740,57 +6717,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7272,7 +7272,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7285,7 +7285,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7293,11 +7293,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7351,87 +7351,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7784,11 +7784,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/kn/LC_MESSAGES/django.po b/plinth/locale/kn/LC_MESSAGES/django.po index 573125457..2a695fee2 100644 --- a/plinth/locale/kn/LC_MESSAGES/django.po +++ b/plinth/locale/kn/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2020-07-16 16:41+0000\n" "Last-Translator: Yogesh \n" "Language-Team: Kannada http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6166,7 +6166,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6308,7 +6308,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6317,20 +6317,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6668,14 +6668,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6683,25 +6683,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6710,30 +6710,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6742,57 +6719,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7274,7 +7274,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7287,7 +7287,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7295,11 +7295,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7353,87 +7353,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7786,11 +7786,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/lt/LC_MESSAGES/django.po b/plinth/locale/lt/LC_MESSAGES/django.po index 886091940..701c00ee0 100644 --- a/plinth/locale/lt/LC_MESSAGES/django.po +++ b/plinth/locale/lt/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Lithuanian http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6166,7 +6166,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6308,7 +6308,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6317,22 +6317,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2P Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6670,14 +6670,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6685,25 +6685,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6712,30 +6712,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6744,57 +6721,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7276,7 +7276,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7289,7 +7289,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7297,11 +7297,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7355,87 +7355,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7788,11 +7788,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/lv/LC_MESSAGES/django.po b/plinth/locale/lv/LC_MESSAGES/django.po index f25547236..065754dd2 100644 --- a/plinth/locale/lv/LC_MESSAGES/django.po +++ b/plinth/locale/lv/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:20+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Latvian http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6165,7 +6165,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6307,7 +6307,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6316,22 +6316,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2P Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6669,14 +6669,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6684,25 +6684,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6711,30 +6711,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6743,57 +6720,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7275,7 +7275,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7288,7 +7288,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7296,11 +7296,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7354,87 +7354,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7787,11 +7787,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/nb/LC_MESSAGES/django.po b/plinth/locale/nb/LC_MESSAGES/django.po index 187e257a6..9ba3b4f57 100644 --- a/plinth/locale/nb/LC_MESSAGES/django.po +++ b/plinth/locale/nb/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2023-08-16 06:52+0000\n" "Last-Translator: Petter Reinholdtsen \n" "Language-Team: Norwegian Bokmål http://config.privoxy.org/ eller http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Mellomtjener for nettet" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Tilgang {url} med mellomtjener {proxy} på tcp{kind}" @@ -7203,7 +7203,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Filsynkronisering" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7376,7 +7376,7 @@ msgstr "Oppdaterer oppsett" msgid "Error configuring app: {error}" msgstr "Feil ved programinstallering: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7385,22 +7385,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "Tor Socks Proxy" msgid "Tor Proxy" msgstr "Tor Socks-mellomtjener" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor Socks-mellomtjener" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Adgang til URL {url} på tcp{kind} via Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bekreft Tor-bruk på {url} via tcp{kind}" @@ -7807,7 +7807,7 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "Starter test av distribusjonsoppgradering." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7818,7 +7818,7 @@ msgstr "" "kan kreve at en brukerkonto er medlem av en gruppe for å gi brukeren tilgang " "til programmet." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7829,25 +7829,25 @@ msgstr "" "liste over programmer som er relevante for dem på hjemmesiden. Dog kan kun " "brukere av admin-gruppen endre programmer eller systeminnstillinger." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Brukere og grupper" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Tilgang til alle tjenester og systeminnstillinger" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Sjekk LDAP-oppføring «{search_item}»" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7856,31 +7856,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "Brukernavnet er opptatt eller reservert." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Skriv et gyldig brukernavn." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Påkrevd. 150 tegn eller mindre. Kun engelske bokstaver, tall og @/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Tilgangspassord" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "Skriv inn passordet for bruker «{user}» for å tillate kontoendringer." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Ugyldig passord." - -#: modules/users/forms.py:112 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 " @@ -7894,21 +7870,45 @@ msgstr "" "gruppen kan logge seg på alle tjenester. De kan også logge inn på systemet " "via SSH, og ha administrative rettigheter (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Skriv et gyldig brukernavn." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Påkrevd. 150 tegn eller mindre. Kun engelske bokstaver, tall og @/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Tilgangspassord" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "Skriv inn passordet for bruker «{user}» for å tillate kontoendringer." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Ugyldig passord." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Oppretting av LDAP-bruker mislyktes: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Klarte ikke å legge ny bruker til i {group}-gruppen: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Autoriserte SSH-nøkler" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7918,38 +7918,38 @@ msgstr "" "på systemet uten å bruke passord. Du kan legge inn multiple (flere) nøkler, " "én på hver linje. Blanke linjer og linjer som starter med # vil bli ignorert." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Klarte ikke å bytte navn på LDAP-bruker." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Klarte ikke å slette bruker fra gruppe." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Klarte ikke legge bruker til gruppe." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Klarte ikke sette SSH-nøkler." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 #, fuzzy #| msgid "Failed to add user to group." msgid "Failed to change user status." msgstr "Klarte ikke legge bruker til gruppe." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Klarte ikke å bytte passord for LDAP-bruker." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Klarte ikke å legge til en ny bruker i admin-gruppen: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Brukerkonto er opprettet, du er nå logget inn" @@ -8495,7 +8495,7 @@ msgstr "" "nettstedet eller bloggen. Aktiver kun etter at oppsettet av Wordpress er " "gjennomført." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8508,7 +8508,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8516,11 +8516,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Organiserer fotografier" @@ -8580,101 +8580,101 @@ msgstr "Tjeneste deaktivert: {name}" msgid "Package {package_expression} is not available for install" msgstr "Pakke {expression} er ikke tilgjengelig for installasjon" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Pakke {package_name} er siste versjon ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "installering" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "laster ned" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "mediaendring" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "oppsettsfil: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Installer App-er" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Oppdaterer program" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Feil ved programinstallering: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Feil ved programinstallering: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Feil ved programinstallering: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Feil ved programinstallering: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Program installert." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Program oppdatert" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Installer App-er" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Feil ved programinstallering: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Feil ved programinstallering: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Program installert." -#: setup.py:453 +#: setup.py:513 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -9074,11 +9074,11 @@ msgstr "" "All programdata og oppsett blir permanent borte. Programmet kan installeres " "på nytt igjen." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Oppsett uendret" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "før avinstallering av {app_id}" diff --git a/plinth/locale/nl/LC_MESSAGES/django.po b/plinth/locale/nl/LC_MESSAGES/django.po index c93251fd5..131ee1274 100644 --- a/plinth/locale/nl/LC_MESSAGES/django.po +++ b/plinth/locale/nl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-02-28 10:02+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Dutch http://config.privoxy.org/ of http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Web Proxy" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Gebruik {url} via proxy {proxy} op tcp{kind}" @@ -7106,7 +7106,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Bestandssynchronisatie" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7281,7 +7281,7 @@ msgstr "Configuratie bijwerken" msgid "Error configuring app: {error}" msgstr "Fout bij het configureren van de toepassing: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7295,20 +7295,20 @@ msgstr "" "krijgen tot internet. ISP-censuur kan worden omzeild door upstream bridges " "te gebruiken." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Tor Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor Socks Proxy" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Gebruik URL {url} op tcp{kind} via Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bevestig Tor gebruik met {url} via tcp{kind}" @@ -7709,7 +7709,7 @@ msgstr "Tussentijdse Software Updates zijn ingeschakeld." msgid "Starting distribution upgrade test." msgstr "Start de distributie upgrade test." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7720,7 +7720,7 @@ msgstr "" "apps moet een gebruikersaccount deel uitmaken van een groep om de gebruiker " "toegang te geven tot de toepassing." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7732,25 +7732,25 @@ msgstr "" "die lid zijn van de admin -groep mogen toepassings- of " "systeeminstellingen wijzigen." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Gebruikers en Groepen" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Toegang tot alle diensten en systeeminstellingen" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Zoek LDAP item \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Controleer nslcd configuratie \"{key} {value}\"" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Controleer nsswitch config \"{database}\"" @@ -7759,32 +7759,7 @@ msgstr "Controleer nsswitch config \"{database}\"" msgid "Username is taken or is reserved." msgstr "Gebruikersnaam is in gebruik of is gereserveerd." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Voer een geldige gebruikersnaam in." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "Vereist. 150 tekens of minder. Alleen letters, cijfers en @/./-/_ ." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Authorisatie-wachtwoord" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Voer het wachtwoord voor gebruiker \"{user}\" in om accountwijzigingen toe " -"te staan." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Ongeldig wachtwoord." - -#: modules/users/forms.py:112 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 " @@ -7799,21 +7774,46 @@ msgstr "" "ook op het systeem inloggen met SSH en kunnen systeemadministratie doen " "(sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Voer een geldige gebruikersnaam in." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "Vereist. 150 tekens of minder. Alleen letters, cijfers en @/./-/_ ." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Authorisatie-wachtwoord" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Voer het wachtwoord voor gebruiker \"{user}\" in om accountwijzigingen toe " +"te staan." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Ongeldig wachtwoord." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "LDAP gebruiker aanmaken mislukt: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Toevoegen van gebruiker aan groep {group} mislukt: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Geautoriseerde SSH-sleutels" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7824,36 +7824,36 @@ msgstr "" "meerdere sleutels toevoegen, één op elke regel. Lege regels en regels die " "beginnen met # worden genegeerd." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "LDAP gebruiker hernoemen mislukt." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Gebruiker uit groep verwijderen mislukt." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Gebruiker aan groep toevoegen mislukt." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Kan de SSH-sleutels niet instellen." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Gebruikerstatus aanpassen mislukt." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Wijzigen LDAP gebruikerswachtwoord mislukt." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Toevoegen van gebruiker aan admin groep mislukt: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Gebruikersaccount aangemaakt, je bent nu ingelogd" @@ -8397,7 +8397,7 @@ msgstr "" "WordPress-site of blog bekijken. Alleen inschakelen na het uitvoeren van de " "eerste WordPress-configuratie." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8419,7 +8419,7 @@ msgstr "" "van zoekwoorden, kaart- en kalenderweergaven. Individuele foto's kunnen met " "anderen worden gedeeld door een directe link te sturen." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8430,11 +8430,11 @@ msgstr "" "Zoph. Voor extra gebruikers moeten zowel in {box_name} als in Zoph accounts " "worden aangemaakt met dezelfde gebruikersnaam." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Foto Organisator" @@ -8493,87 +8493,87 @@ msgstr "Klaar: {name}" msgid "Package {package_expression} is not available for install" msgstr "Pakket {package_expression} is niet beschikbaar voor installatie" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Pakket {package_name} is de nieuwste versie ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "installeren" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "downloaden" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "media wijzigen" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "configuratiebestand: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Time-out wachtend op pakketbeheerder" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Toepassing installeren" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Toepassing updaten" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Fout bij het installeren van de toepassing: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Fout bij het bijwerken van de toepassing: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Fout bij het installeren van de toepassing: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Fout bij het bijwerken van de toepassing: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "De toepassing is geïnstalleerd." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Toepassing bijgewerkt" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Toepassing wordt verwijderd" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Fout bij het verwijderen van de toepassing: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Fout bij het verwijderen van de toepassing: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "De toepassing is verwijderd." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Toepassings-pakketten bijwerken" @@ -8967,11 +8967,11 @@ msgstr "" "Alle toepassings-gegevens en configuratie gaan permanent verloren. de " "toepassing kan opnieuw vers worden geïnstalleerd." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Instelling onveranderd" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "voor het verwijderen van {app_id}" diff --git a/plinth/locale/pl/LC_MESSAGES/django.po b/plinth/locale/pl/LC_MESSAGES/django.po index b0301b334..89b377be3 100644 --- a/plinth/locale/pl/LC_MESSAGES/django.po +++ b/plinth/locale/pl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Polish http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6651,7 +6651,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6802,7 +6802,7 @@ msgstr "Podczas konfiguracji wystąpił błąd." msgid "Error configuring app: {error}" msgstr "Błąd podczas instalowania aplikacji: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6811,22 +6811,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2P Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -7200,14 +7200,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "Rejestracja użytkowników wyłączona" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7215,25 +7215,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7242,36 +7242,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid server name" -msgid "Enter a valid username." -msgstr "Niewłaściwa nazwa użytkownika" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -#, fuzzy -#| msgid "Administrator Account" -msgid "Authorization Password" -msgstr "Konto Administratora" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -#, fuzzy -#| msgid "Show password" -msgid "Invalid password." -msgstr "Pokaż hasło" - -#: modules/users/forms.py:112 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 " @@ -7280,59 +7251,88 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid server name" +msgid "Enter a valid username." +msgstr "Niewłaściwa nazwa użytkownika" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +#, fuzzy +#| msgid "Administrator Account" +msgid "Authorization Password" +msgstr "Konto Administratora" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Show password" +msgid "Invalid password." +msgstr "Pokaż hasło" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Tworzenie użytkownika LDAP nie udało się: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Nieudane dodanie użytkownika do {group} grupy:{error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 #, fuzzy #| msgid "Failed to add new user to admin group." msgid "Failed to change user status." msgstr "Nieudane dodawanie użytkownika do grupy admin." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Nieudane dodawanie użytkownika do grupy admin: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Utworzono konto użytkownika, możesz się teraz zalogować" @@ -7869,7 +7869,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7882,7 +7882,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7890,11 +7890,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7951,103 +7951,103 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "plik konfiguracyjny: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Instaluj aplikacje" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Błąd podczas instalowania aplikacji: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Błąd podczas instalowania aplikacji: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Błąd podczas instalowania aplikacji: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Błąd podczas instalowania aplikacji: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikacja zainstalowania." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Ostatnie uaktualnienie" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Instaluj aplikacje" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Błąd podczas instalowania aplikacji: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Błąd podczas instalowania aplikacji: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikacja zainstalowania." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8457,11 +8457,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Ustawienie bez zmian" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/pt/LC_MESSAGES/django.po b/plinth/locale/pt/LC_MESSAGES/django.po index 2812035ee..04ca1dcfc 100644 --- a/plinth/locale/pt/LC_MESSAGES/django.po +++ b/plinth/locale/pt/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2023-05-22 15:50+0000\n" "Last-Translator: Frederico Gomes \n" "Language-Team: Portuguese http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Acesse {url} com proxy {proxy} em tcp{kind}" @@ -6506,7 +6506,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6657,7 +6657,7 @@ msgstr "Configuração Geral" msgid "Error configuring app: {error}" msgstr "Erro a instalar a aplicação: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6666,22 +6666,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2P Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -7037,14 +7037,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "A iniciar teste de atualização de distribuição." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7052,25 +7052,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7079,30 +7079,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Insira um nome de utilizador válido." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Palavra-passe inválida." - -#: modules/users/forms.py:112 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 " @@ -7111,57 +7088,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Insira um nome de utilizador válido." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Palavra-passe inválida." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Conta de utilizador criada, a sua sessão já foi iniciada" @@ -7669,7 +7669,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7682,7 +7682,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7690,11 +7690,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7748,105 +7748,105 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 #, fuzzy #| msgid "Setting unchanged" msgid "media change" msgstr "Definição inalterada" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "ficheiro de configuração: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install" msgid "Installing app" msgstr "Instalar" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Erro a instalar a aplicação: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Erro a instalar a aplicação: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Erro a instalar a aplicação: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Erro a instalar a aplicação: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplicação instalada." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Name" msgid "App updated" msgstr "Nome" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install" msgid "Uninstalling app" msgstr "Instalar" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Erro a instalar a aplicação: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Erro a instalar a aplicação: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplicação instalada." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8218,11 +8218,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Definição inalterada" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/ru/LC_MESSAGES/django.po b/plinth/locale/ru/LC_MESSAGES/django.po index 30191b0ba..57513fa3f 100644 --- a/plinth/locale/ru/LC_MESSAGES/django.po +++ b/plinth/locale/ru/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-10-10 18:05+0000\n" "Last-Translator: Nikita Epifanov \n" "Language-Team: Russian http://config.privoxy.org или http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Web-прокси" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Доступ к {url} с прокси {proxy} на tcp{kind}" @@ -7134,7 +7134,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Синхронизация файлов" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7310,7 +7310,7 @@ msgstr "Произошла ошибка во время настройки." msgid "Error configuring app: {error}" msgstr "Ошибка при установке приложения: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7319,22 +7319,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "Tor Socks Proxy" msgid "Tor Proxy" msgstr "Tor Socks прокси" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor Socks прокси" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Доступ к {url} по tcp{kind} через Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Подтверждение использования Tor в {url} по tcp {kind}" @@ -7743,7 +7743,7 @@ msgstr "Активированы частые обновления функци msgid "Starting distribution upgrade test." msgstr "Обновление дистрибутива включено" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7755,7 +7755,7 @@ msgstr "" "запись пользователя была частью группы, чтобы разрешить пользователю доступ " "к приложению." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7767,25 +7767,25 @@ msgstr "" "пользователи группы admin могут изменять приложения или системные " "настройки." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Пользователи и группы" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Доступ ко всем сервисам и настройкам системы" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Проверьте запись LDAP \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7794,33 +7794,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "Имя пользователя уже занято." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Введите действительное имя пользователя." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Требуется. 150 символов или меньше. Только английские буквы, цифры и @/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Пароль авторизации" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Введите пароль пользователя \"{user}\" для авторизации изменений учетной " -"записи." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Неправильный пароль." - -#: modules/users/forms.py:112 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 " @@ -7834,21 +7808,47 @@ msgstr "" "\"admin\" смогут войти во все службы. Они также могут входить в систему " "через SSH и иметь привилегии администратора (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Введите действительное имя пользователя." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Требуется. 150 символов или меньше. Только английские буквы, цифры и @/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Пароль авторизации" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Введите пароль пользователя \"{user}\" для авторизации изменений учетной " +"записи." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Неправильный пароль." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Не удалось создать пользователя LDAP: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Не удалось добавить нового пользователя в группу {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Авторизованные SSH ключи" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7859,37 +7859,37 @@ msgstr "" "на каждой строке. Пустые строки и строки, начинающиеся с # будут " "игнорироваться." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Переименование пользователя LDAP не удалось." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Не удалось удалить пользователя из группы." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Не удалось добавить пользователя в группу." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Не удалось задать ключи SSH." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Не удалось изменить статус пользователя." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Изменение LDAP пароля пользователя не удалось." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Не удалось добавить нового пользователя в группу администраторов: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Учетная запись пользователя создана, теперь вы вошли" @@ -8435,7 +8435,7 @@ msgstr "" "просматривать сайт или блог WordPress. Включайте только после первоначальной " "настройки WordPress." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8458,7 +8458,7 @@ msgstr "" "месте. Отдельными фотографиями можно поделиться с другими, отправив прямую " "ссылку." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8469,11 +8469,11 @@ msgstr "" "Zoph. Для дополнительных пользователей необходимо создать учетные записи как " "в {box_name}, так и в Zoph с тем же именем пользователя." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Организатор фотографий" @@ -8534,105 +8534,105 @@ msgstr "Служба выключена: {name}" msgid "Package {package_expression} is not available for install" msgstr "Пакет {expression} недоступен для установки" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Пакет {package_name} последней версией ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "Установка" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "Загрузка" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "изменение медиа" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "Файл настроек: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "Установка приложений" -#: setup.py:43 +#: setup.py:41 #, fuzzy #| msgid "Updating..." msgid "Updating app" msgstr "Обновляется..." -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Ошибка при установке пакетов: {string}{details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Ошибка при установке пакетов: {string}{details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Ошибка при установке приложения: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Ошибка при установке приложения: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Приложение установлено." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "Последнее обновление" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "Установка приложений" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Ошибка при установке пакетов: {string}{details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Ошибка при установке приложения: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Приложение установлено." -#: setup.py:453 +#: setup.py:513 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -9032,11 +9032,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Настройки без изменений" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/si/LC_MESSAGES/django.po b/plinth/locale/si/LC_MESSAGES/django.po index ce9f8d5ad..9116bb333 100644 --- a/plinth/locale/si/LC_MESSAGES/django.po +++ b/plinth/locale/si/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2021-04-27 13:32+0000\n" "Last-Translator: HelaBasa \n" "Language-Team: Sinhala http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6164,7 +6164,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6306,7 +6306,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6315,20 +6315,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6666,14 +6666,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6681,25 +6681,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6708,30 +6708,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6740,57 +6717,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7272,7 +7272,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7285,7 +7285,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7293,11 +7293,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7351,87 +7351,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7784,11 +7784,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/sl/LC_MESSAGES/django.po b/plinth/locale/sl/LC_MESSAGES/django.po index 0dceb7a79..98bdb5851 100644 --- a/plinth/locale/sl/LC_MESSAGES/django.po +++ b/plinth/locale/sl/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:19+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Slovenian http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6424,7 +6424,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6569,7 +6569,7 @@ msgstr "Konfiguracija je posodobljena" msgid "Error configuring app: {error}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6578,22 +6578,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2P Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6955,14 +6955,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6970,25 +6970,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6997,34 +6997,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -#, fuzzy -#| msgid "Invalid hostname" -msgid "Enter a valid username." -msgstr "Neveljavno ime gostitelja" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -#, fuzzy -#| msgid "Invalid hostname" -msgid "Invalid password." -msgstr "Neveljavno ime gostitelja" - -#: modules/users/forms.py:112 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 " @@ -7033,57 +7006,84 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +#, fuzzy +#| msgid "Invalid hostname" +msgid "Enter a valid username." +msgstr "Neveljavno ime gostitelja" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +#, fuzzy +#| msgid "Invalid hostname" +msgid "Invalid password." +msgstr "Neveljavno ime gostitelja" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7597,7 +7597,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7610,7 +7610,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7618,11 +7618,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7677,101 +7677,101 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Napaka ob nameščanju aplikacije: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Napaka ob nameščanju aplikacije: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikacija je nameščena." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Name" msgid "App updated" msgstr "Ime" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Napaka ob nameščanju aplikacije: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Napaka ob nameščanju aplikacije: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikacija je nameščena." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8131,11 +8131,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/sq/LC_MESSAGES/django.po b/plinth/locale/sq/LC_MESSAGES/django.po index f852ab91c..a2448dd7c 100644 --- a/plinth/locale/sq/LC_MESSAGES/django.po +++ b/plinth/locale/sq/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-02-13 01:32+0000\n" "Last-Translator: Besnik Bleta \n" "Language-Team: Albanian . Parashtrimi bëhet përmes rrjetit Tor, për anonimitet shtesë, " "nëse është i aktivizuar aplikacioni Tor." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5635,7 +5635,7 @@ msgstr "" "faqesh web dhe kryesh HTTP, kontrollim hyrjesh, dhe heqje reklamash dhe të " "tjera hedhurina të papëlqyeshme Internet. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5652,15 +5652,15 @@ msgstr "" "te http://config.privoxy.org/ ose " "http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Ndërmjetës Web" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Hapni {url} me ndërmjetësin {proxy} në tcp{kind}" @@ -7137,7 +7137,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Njëkohësim Kartelash" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7311,7 +7311,7 @@ msgstr "Po përditësohet formësimi" msgid "Error configuring app: {error}" msgstr "Gabim në formësimin e aplikacionit: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7325,20 +7325,20 @@ msgstr "" "rrjetit Tor-in. Censurimi nga ISP-të mund të anashkalohen duke përdorur ura " "“upstream”." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Ndërmjetës Tor" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Ndërmjetës SOCKS Tor" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "URL hyrjesh {url} në tcp{kind} përmes Tor-i" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Ripohoni përdorim Tor-i te {url} në tcp{kind}" @@ -7746,7 +7746,7 @@ msgstr "Përditësime të shpeshta veçorish të aktivizuara." msgid "Starting distribution upgrade test." msgstr "Po fillohet provë përmirësimi shpërndarjeje." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7757,7 +7757,7 @@ msgstr "" "aplikacione kërkojnë doemos një llogari përdoruesi, për të qenë pjesë e një " "grupi që autorizon përdoruesin të përdorë aplikacionin." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7769,25 +7769,25 @@ msgstr "" "vetëm përdoruesit e grupit përgjegjës mund të ndryshojnë " "aplikacionet, apo rregullimet e sistemit." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Përdorues dhe Grupe" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Hyrje te krejt shërbimet dhe rregullime të sistemit" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Kontrolloni zërin LDAP \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Kontrolloni “{key} {value}” formësimi nslcd-je" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Kontrolloni “{database}” formësimi nsswitch" @@ -7796,34 +7796,7 @@ msgstr "Kontrolloni “{database}” formësimi nsswitch" msgid "Username is taken or is reserved." msgstr "Emri i përdoruesit është i zënë, ose i rezervuar." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Jepni një emër përdoruesi të vlefshëm." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"E domosdoshme. 150 ose më pak shenja. Vetëm shkronja anglishteje, shifra, " -"dhe @/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Fjalëkalim Autorizimi" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Jepni fjalëkalimin për përdoruesin “{user}”, që të autorizoni ndryshime " -"llogarie." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Fjalëkalim i pavlefshëm." - -#: modules/users/forms.py:112 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 " @@ -7838,21 +7811,48 @@ msgstr "" "në krejt shërbimet. Munden edhe të hyjnë në sistem përmes SSH-së dhe të kenë " "privilegje administrative (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Jepni një emër përdoruesi të vlefshëm." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"E domosdoshme. 150 ose më pak shenja. Vetëm shkronja anglishteje, shifra, " +"dhe @/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Fjalëkalim Autorizimi" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Jepni fjalëkalimin për përdoruesin “{user}”, që të autorizoni ndryshime " +"llogarie." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Fjalëkalim i pavlefshëm." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "S’u arrit të krijohej përdorues LDAP: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "S’u arrit të shtohej përdorues i ri te grupi {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Kyçe SSH të autorizuar" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7863,36 +7863,36 @@ msgstr "" "një për rresht. Rreshta të zbrazët dhe rreshta që fillojnë me # do të " "shpërfillen." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Riemërtimi i përdoruesit LDAP dështoi." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "S’u arrit të hiqej përdorues nga grupi." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "S’u arrit të shtohej përdorues te grup." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "S’arrihet të ujdisen kyçe SSH." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "S’u arrit të ndryshohej gjendje përdoruesi." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Ndryshimi i fjalëkalimit për përdorues LDAP dështoi." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "S’u arrit të shtohej përdorues i ri te grupi i përgjegjësve: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Llogaria e përdoruesit u krijua, tani jeni i futur në llogari" @@ -8436,7 +8436,7 @@ msgstr "" "sajtin ose blogun WordPress. Aktivizojeni vetëm pasi të jetë kryer ujdisja " "fillestare e WordPress-it." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8458,7 +8458,7 @@ msgstr "" "pamjet hartë dhe kalendar. Foto individuale mund të ndahen me të tjerë duke " "dërguar një lidhje të drejtpërdrejtë." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8469,11 +8469,11 @@ msgstr "" "Zoph. Për përdorues të tjerë, llogaritë mund të krijohen si në {box_name}, " "ashtu edhe në Zoph, me të njëjtin emër përdoruesi." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Sistemues Fotografish" @@ -8531,88 +8531,88 @@ msgstr "Përfundoi: {name}" msgid "Package {package_expression} is not available for install" msgstr "Paketa {package_expression} s’është e gatshme për instalim" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" "Paketa {package_name} gjendet nën versionin më të ri ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "po instalohet" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "po shkarkohet" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "ndryshim media" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "kartelë formësimi: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Mbaroi koha teksa pritej për përgjegjës paketash" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Po instalohet aplikacioni" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Po përditësohet aplikacioni" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Gabim në instalimin e aplikacionit: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Gabim në përditësimin e aplikacionit: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Gabim në instalimin e aplikacionit: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Gabim në përditësimin e aplikacionit: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "Aplikacioni u instalua." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Aplikacioni u përditësua" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Po çinstalohet aplikacion" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Gabim në çinstalimin e aplikacionit: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Gabim në çinstalimin e aplikacionit: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Aplikacioni u çinstalua." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Po përditësohet paketa aplikacioni" @@ -9005,11 +9005,11 @@ msgstr "" "Krejt të dhënat dhe formësimi i aplikacionit do të humbin përgjithnjë. " "Aplikacioni mund të instalohet sërish nga e para." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Rregullim i pandryshuar" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "para çinstalimit të {app_id}" diff --git a/plinth/locale/sr/LC_MESSAGES/django.po b/plinth/locale/sr/LC_MESSAGES/django.po index 2c392ac99..366be51c6 100644 --- a/plinth/locale/sr/LC_MESSAGES/django.po +++ b/plinth/locale/sr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2022-09-14 17:20+0000\n" "Last-Translator: ikmaak \n" "Language-Team: Serbian http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6294,7 +6294,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6439,7 +6439,7 @@ msgstr "Konfiguracija sačuvana" msgid "Error configuring app: {error}" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6448,22 +6448,22 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 #, fuzzy #| msgid "I2P Proxy" msgid "Tor Proxy" msgstr "I2P Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6811,14 +6811,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6826,25 +6826,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6853,30 +6853,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6885,57 +6862,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7417,7 +7417,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7430,7 +7430,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7438,11 +7438,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7496,99 +7496,99 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Greška prilikom instaliranja aplikacije: {string}{details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Greška prilikom instaliranja aplikacije: {string}{details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Aplikacija instalirana." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Greška prilikom instaliranja aplikacije: {string}{details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Greška prilikom instaliranja aplikacije: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Aplikacija instalirana." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7947,11 +7947,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/sv/LC_MESSAGES/django.po b/plinth/locale/sv/LC_MESSAGES/django.po index b69149d07..707e8535c 100644 --- a/plinth/locale/sv/LC_MESSAGES/django.po +++ b/plinth/locale/sv/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-02-02 20:01+0000\n" "Last-Translator: bittin1ddc447d824349b2 \n" "Language-Team: Swedish popcon.debian.org. Inlämningen sker via Tor-nätverket " "för ytterligare anonymitet om Tor-appen är aktiverad." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5587,7 +5587,7 @@ msgstr "" "för att förbättra sekretessen, ändra webbsidan data och HTTP-huvuden, " "kontrollera åtkomst och ta bort annonser och andra avskyvärda Internet Junk. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5603,15 +5603,15 @@ msgstr "" "href=\"http://config.privoxy.org\">http://config.privoxy.org/ eller http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Webbproxy" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Anslut till {url} med proxy {proxy} på TCP {kind}" @@ -7069,7 +7069,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Filsynkronisering" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7241,7 +7241,7 @@ msgstr "Uppdatera konfigurationen" msgid "Error configuring app: {error}" msgstr "Fel vid konfigurering av appen: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7254,20 +7254,20 @@ msgstr "" "appar för att komma åt internet via Tor-nätverket. ISP-censur kan kringgås " "med hjälp av uppströms broar." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Tor Proxy" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor SOCKS-proxy" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Tillgång URL {url} på TCP {kind} via Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Bekräfta Tor-användning vid {url} på TCP {kind}" @@ -7671,7 +7671,7 @@ msgstr "Frekventa funktionsuppdateringar aktiverade." msgid "Starting distribution upgrade test." msgstr "Startar distributionsuppgraderingstest." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7682,7 +7682,7 @@ msgstr "" "ett användarkonto för att vara en del av en grupp för att auktorisera " "användaren att komma åt appen." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7693,25 +7693,25 @@ msgstr "" "över appar som är relevanta för dem på startsidan. Endast användare av " "gruppen admin kan dock ändra appar eller Systeminställningar." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Användare och grupper" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Tillgång till alla tjänster och systeminställningar" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Kontrollera LDAP-posten \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Kontrollera nslcd-konfigurationen \"{key}{value}\"" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Kontrollera nsswitch-konfigurationen \"{database}\"" @@ -7720,34 +7720,7 @@ msgstr "Kontrollera nsswitch-konfigurationen \"{database}\"" msgid "Username is taken or is reserved." msgstr "Användarnamnet är upptaget eller är reserverade." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Ange ett giltigt användarnamn." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Krävs. 150 tecken eller färre. Engelska bokstäver, siffror och endast @/./-/" -"_ ." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Auktoriseringslösenord" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Ange lösenordet för användaren \"{user}\" för att godkänna " -"kontomodifieringar." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Ogiltigt lösenord." - -#: modules/users/forms.py:112 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 " @@ -7761,21 +7734,48 @@ msgstr "" "administratörsgruppen kommer att kunna logga in på alla tjänster. De kan " "också logga in på systemet via SSH och har administratörsprivilegier (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Ange ett giltigt användarnamn." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Krävs. 150 tecken eller färre. Engelska bokstäver, siffror och endast @/./-/" +"_ ." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Auktoriseringslösenord" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Ange lösenordet för användaren \"{user}\" för att godkänna " +"kontomodifieringar." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Ogiltigt lösenord." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Det gick inte att skapa LDAP-användare: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Det gick inte att lägga till ny användare i gruppen {group} : {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Auktoriserade SSH-nycklar" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7785,37 +7785,37 @@ msgstr "" "systemet utan att använda ett lösenord. Du kan ange flera nycklar, en på " "varje rad. Tomma rader och rader som börjar med # kommer att ignoreras." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Det gick inte att byta namn på LDAP-användare." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Det gick inte att ta bort användare från gruppen." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Det gick inte att lägga till användare i gruppen." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Det går inte att ange SSH-nycklar." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Det gick inte att ändra användarstatus." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Det gick inte att ändra användarlösenordet för LDAP." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" "Det gick inte att lägga till ny användare i administratörsgruppen: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Användarkonto skapat, du är nu inloggad" @@ -8356,7 +8356,7 @@ msgstr "" "WordPress-webbplatsen eller bloggen. Aktivera endast efter den första " "installationen av WordPress." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8377,7 +8377,7 @@ msgstr "" "på en plats med hjälp av sök-, kart- och kalendervyer. Enskilda foton kan " "delas med andra genom att skicka en direktlänk." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8388,11 +8388,11 @@ msgstr "" "i Zoph. För ytterligare användare måste konton skapas både i {box_name} och " "i Zoph med samma användarnamn." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Foto Organizer" @@ -8450,87 +8450,87 @@ msgstr "Avslutad: {name}" msgid "Package {package_expression} is not available for install" msgstr "Paket {package_expression} är inte tillgänglig för installation" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Paketet {package_name} är den senaste versionen ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "Installera" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "ladda ner" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "Mediabyte" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "konfigurationsfil: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Timeout väntar på pakethanteraren" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Installera app" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Uppdatera app" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Fel vid installation av app: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Fel vid uppdatering av app: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Fel vid installation av app: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Fel vid uppdatering av app: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "App installerad." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "App uppdaterad" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Avinstallera app" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Fel vid avinstallation av app: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Fel vid avinstallation av appen: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Appen avinstallerad." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Uppdatera appaket" @@ -8925,11 +8925,11 @@ msgstr "" "All appdata och konfiguration kommer att gå förlorad permanent. Appen kan " "installeras på nytt igen." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Instänllningar oförändrade" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "innan du avinstallerar {app_id}" diff --git a/plinth/locale/ta/LC_MESSAGES/django.po b/plinth/locale/ta/LC_MESSAGES/django.po index 20127a019..f44af1dd5 100644 --- a/plinth/locale/ta/LC_MESSAGES/django.po +++ b/plinth/locale/ta/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -27,27 +27,27 @@ msgstr "" msgid "FreedomBox" msgstr "" -#: daemon.py:105 +#: daemon.py:122 #, python-brace-format msgid "Service {service_name} is running" msgstr "" -#: daemon.py:164 +#: daemon.py:218 #, python-brace-format msgid "Listening on {kind} port {listen_address}:{port}" msgstr "" -#: daemon.py:167 +#: daemon.py:221 #, python-brace-format msgid "Listening on {kind} port {port}" msgstr "" -#: daemon.py:236 +#: daemon.py:291 #, python-brace-format msgid "Connect to {host}:{port}" msgstr "" -#: daemon.py:240 +#: daemon.py:299 #, python-brace-format msgid "Cannot connect to {host}:{port}" msgstr "" @@ -113,12 +113,12 @@ msgstr "" msgid "{box_name} Web Interface (Plinth)" msgstr "" -#: modules/apache/components.py:154 +#: modules/apache/components.py:159 #, python-brace-format msgid "Access URL {url} on tcp{kind}" msgstr "" -#: modules/apache/components.py:157 +#: modules/apache/components.py:162 #, python-brace-format msgid "Access URL {url}" msgstr "" @@ -748,7 +748,7 @@ msgid "Permissions for anonymous users, who have not provided a password." msgstr "" #: modules/bepasty/forms.py:27 modules/bepasty/templates/bepasty.html:30 -#: modules/users/forms.py:110 modules/users/forms.py:233 +#: modules/users/forms.py:91 msgid "Permissions" msgstr "" @@ -1320,77 +1320,77 @@ msgstr "" msgid "Bittorrent client written in Python/PyGTK" msgstr "" -#: modules/diagnostics/__init__.py:27 +#: modules/diagnostics/__init__.py:28 msgid "" "The system diagnostic test will run a number of checks on your system to " "confirm that applications and services are working as expected." msgstr "" -#: modules/diagnostics/__init__.py:51 modules/diagnostics/__init__.py:236 +#: modules/diagnostics/__init__.py:52 modules/diagnostics/__init__.py:238 msgid "Diagnostics" msgstr "" -#: modules/diagnostics/__init__.py:95 +#: modules/diagnostics/__init__.py:96 msgid "passed" msgstr "" -#: modules/diagnostics/__init__.py:96 modules/networks/views.py:50 +#: modules/diagnostics/__init__.py:97 modules/networks/views.py:50 msgid "failed" msgstr "" -#: modules/diagnostics/__init__.py:97 +#: modules/diagnostics/__init__.py:98 msgid "error" msgstr "" -#: modules/diagnostics/__init__.py:98 +#: modules/diagnostics/__init__.py:99 msgid "warning" msgstr "" #. Translators: This is the unit of computer storage Mebibyte similar to #. Megabyte. -#: modules/diagnostics/__init__.py:202 +#: modules/diagnostics/__init__.py:204 msgid "MiB" msgstr "" #. Translators: This is the unit of computer storage Gibibyte similar to #. Gigabyte. -#: modules/diagnostics/__init__.py:207 +#: modules/diagnostics/__init__.py:209 msgid "GiB" msgstr "" -#: modules/diagnostics/__init__.py:214 +#: modules/diagnostics/__init__.py:216 msgid "You should disable some apps to reduce memory usage." msgstr "" -#: modules/diagnostics/__init__.py:219 +#: modules/diagnostics/__init__.py:221 msgid "You should not install any new apps on this system." msgstr "" -#: modules/diagnostics/__init__.py:231 +#: modules/diagnostics/__init__.py:233 #, no-python-format, python-brace-format msgid "" "System is low on memory: {percent_used}% used, {memory_available} " "{memory_available_unit} free. {advice_message}" msgstr "" -#: modules/diagnostics/__init__.py:233 +#: modules/diagnostics/__init__.py:235 msgid "Low Memory" msgstr "" -#: modules/diagnostics/__init__.py:264 +#: modules/diagnostics/__init__.py:266 msgid "Running diagnostics" msgstr "" -#: modules/diagnostics/__init__.py:307 +#: modules/diagnostics/__init__.py:309 #, no-python-format, python-brace-format msgid "Found {issue_count} issues during routine tests." msgstr "" -#: modules/diagnostics/__init__.py:308 +#: modules/diagnostics/__init__.py:310 msgid "Diagnostics results" msgstr "" -#: modules/diagnostics/__init__.py:313 +#: modules/diagnostics/__init__.py:315 msgid "Go to diagnostics results" msgstr "" @@ -1466,7 +1466,7 @@ msgstr "" msgid "Result" msgstr "" -#: modules/diagnostics/views.py:107 +#: modules/diagnostics/views.py:111 msgid "Diagnostic Test" msgstr "" @@ -1590,7 +1590,7 @@ msgid "Use HTTP basic authentication" msgstr "" #: modules/dynamicdns/forms.py:88 modules/networks/forms.py:207 -#: modules/users/forms.py:67 +#: modules/users/forms.py:117 msgid "Username" msgstr "" @@ -1958,29 +1958,29 @@ msgstr "" msgid "Firewall" msgstr "" -#: modules/firewall/__init__.py:271 +#: modules/firewall/__init__.py:272 msgid "Default zone is external" msgstr "" -#: modules/firewall/__init__.py:280 +#: modules/firewall/__init__.py:282 msgid "Firewall backend is nftables" msgstr "" -#: modules/firewall/__init__.py:293 +#: modules/firewall/__init__.py:296 msgid "Direct passthrough rules exist" msgstr "" -#: modules/firewall/components.py:136 +#: modules/firewall/components.py:139 #, python-brace-format msgid "Port {name} ({details}) available for internal networks" msgstr "" -#: modules/firewall/components.py:147 +#: modules/firewall/components.py:153 #, python-brace-format msgid "Port {name} ({details}) available for external networks" msgstr "" -#: modules/firewall/components.py:153 +#: modules/firewall/components.py:159 #, python-brace-format msgid "Port {name} ({details}) unavailable for external networks" msgstr "" @@ -2098,11 +2098,11 @@ msgstr "" msgid "Read-write access to Git repositories" msgstr "" -#: modules/gitweb/__init__.py:50 modules/gitweb/manifest.py:11 +#: modules/gitweb/__init__.py:48 modules/gitweb/manifest.py:11 msgid "Gitweb" msgstr "" -#: modules/gitweb/__init__.py:51 +#: modules/gitweb/__init__.py:49 msgid "Simple Git Hosting" msgstr "" @@ -2539,7 +2539,7 @@ msgid "I2P" msgstr "" #: modules/i2p/__init__.py:53 modules/tor/__init__.py:63 -#: modules/torproxy/__init__.py:56 +#: modules/torproxy/__init__.py:57 msgid "Anonymity Network" msgstr "" @@ -3498,19 +3498,19 @@ msgstr "" msgid "Services" msgstr "" -#: modules/networks/__init__.py:35 +#: modules/networks/__init__.py:36 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: modules/networks/__init__.py:37 +#: modules/networks/__init__.py:38 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: modules/networks/__init__.py:58 +#: modules/networks/__init__.py:59 msgid "Networks" msgstr "" @@ -4873,14 +4873,14 @@ msgid "" "network for additional anonymity if Tor app is enabled." msgstr "" -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " "access, and removing ads and other obnoxious Internet junk. " msgstr "" -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -4891,15 +4891,15 @@ msgid "" "p\">http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6163,7 +6163,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6305,7 +6305,7 @@ msgstr "" msgid "Error configuring app: {error}" msgstr "" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6314,20 +6314,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6665,14 +6665,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6680,25 +6680,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6707,30 +6707,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6739,57 +6716,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7271,7 +7271,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7284,7 +7284,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7292,11 +7292,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7350,87 +7350,87 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7783,11 +7783,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/te/LC_MESSAGES/django.po b/plinth/locale/te/LC_MESSAGES/django.po index 596066e02..0fe0437fc 100644 --- a/plinth/locale/te/LC_MESSAGES/django.po +++ b/plinth/locale/te/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: FreedomBox UI\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-02-11 20:14+0000\n" "Last-Translator: Sunil Mohan Adapa \n" "Language-Team: Telugu popcon.debian.orgలో పబ్లిక్‌గా అందుబాటులో ఉన్నాయి. టోర్ యాప్ " "ప్రారంభించబడితే అదనపు అజ్ఞాతం కోసం టోర్ నెట్‌వర్క్ ద్వారా సమర్పణ జరుగుతుంది." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5404,7 +5404,7 @@ msgstr "" "నియంత్రించడం మరియు ప్రకటనలను మరియు ఇతర చెడ్డ ఇంటర్నెట్ వ్యర్థాలను తొలగించడం కోసం ఆధునిక ఫిల్టరింగ్ " "సామర్థ్యాలతో ఒక కాని క్యాచింగ్ వెబ్ ప్రాక్సీ. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, fuzzy, python-brace-format #| msgid "" #| "You can use Privoxy by modifying your browser proxy settings to your " @@ -5425,15 +5425,15 @@ msgstr "" "డాక్యుమెంటేషన్ http://config.privoxy.org/ లేదా http://p.p లో చూడవచ్చు." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "ప్రివొక్సి" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "వెబ్ ప్రాక్సీ" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "టీసీపీ{kind} పై{proxy} తో యాక్సిస్ {url} చేయండి" @@ -6868,7 +6868,7 @@ msgstr "సింక్ తింగ్" msgid "File Synchronization" msgstr "ఫైళ్ళ సమకాలీకరణ" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7034,7 +7034,7 @@ msgstr "కాన్ఫిగరేషన్‌ను నవీకరిస్ msgid "Error configuring app: {error}" msgstr "యాప్‌ని కాన్ఫిగర్ చేయడంలో లోపం: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7046,20 +7046,20 @@ msgstr "" "ప్రాక్సీని అందిస్తుంది. Tor నెట్‌వర్క్ ద్వారా ఇంటర్నెట్‌ను యాక్సెస్ చేయడానికి వివిధ యాప్‌ల ద్వారా దీన్ని " "ఉపయోగించవచ్చు. ISP సెన్సార్‌షిప్‌ను అప్‌స్ట్రీమ్ వంతెనలను ఉపయోగించి తప్పించుకోవచ్చు." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "టోర్ ప్రాక్సీ" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "టోర్ సాక్స్ ప్రాతినిధ్య" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "టార్ ద్వారా {kind} లో {url} ను ఆక్సెస్ చెయ్యండి" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "టోర్ వాడుకను నిర్ధారించండి{url} టీ సి పి పై{kind}" @@ -7445,7 +7445,7 @@ msgstr "తరచుగా ఫీచర్ అప్‌డేట్‌లు య msgid "Starting distribution upgrade test." msgstr "పంపిణీ మెరుగుపరిచే పరిక్ష ప్రారంభించబడింది." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7455,7 +7455,7 @@ msgstr "" "విధానంగా పనిచేస్తాయి. కొన్ని యాప్‌లకు యాప్‌ను యాక్సెస్ చేయడానికి వినియోగదారుని ప్రామాణీకరించడానికి సమూహంలో భాగంగా " "వినియోగదారు ఖాతా అవసరం." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7466,25 +7466,25 @@ msgstr "" "చేయవచ్చు. అయినప్పటికీ, అడ్మిన్ సమూహం యొక్క వినియోగదారులు మాత్రమే యాప్‌లు లేదా సిస్టమ్ " "సెట్టింగ్‌లను మార్చవచ్చు." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "వినియోగదారులు మరియు సమూహాలు" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "అన్ని సేవలకు మరియు సిస్టమ్ అమరికలకు ప్రాప్యత" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP నమోదు \"{search_item}\" తనిఖీ" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -7493,31 +7493,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "యూజర్ పేరు తీసుకోబడింది లేదా రిజర్వ్ చేయబడింది." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "చెల్లుబాటు అయ్యే వినియోగదారు పేరును నమోదు చేయండి." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"అవసరం. 150 అక్షరాలు లేదా అంతకంటే తక్కువ. ఆంగ్ల అక్షరాలు, అంకెలు మరియు @/./-/_ మాత్రమే." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "అధికార రహస్యపదం" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "వినియోగదారు కోసం పాస్‌వర్డ్‌ను నమోదు చేయండి\"{user}\"ఖాతా సవరణలకు అధికారం ఇవ్వడానికి." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "చెల్లని రహస్యపదం." - -#: modules/users/forms.py:112 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 " @@ -7530,21 +7506,45 @@ msgstr "" "అన్ని సేవలకు లాగిన్ చేయగలరు. వారు SSH ద్వారా సిస్టమ్‌కి లాగిన్ అవ్వగలరు మరియు నిర్వాహక అధికారాలను (సూడో) " "కలిగి ఉంటారు." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "చెల్లుబాటు అయ్యే వినియోగదారు పేరును నమోదు చేయండి." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"అవసరం. 150 అక్షరాలు లేదా అంతకంటే తక్కువ. ఆంగ్ల అక్షరాలు, అంకెలు మరియు @/./-/_ మాత్రమే." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "అధికార రహస్యపదం" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "వినియోగదారు కోసం పాస్‌వర్డ్‌ను నమోదు చేయండి\"{user}\"ఖాతా సవరణలకు అధికారం ఇవ్వడానికి." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "చెల్లని రహస్యపదం." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "ల్డప్ వినియోగదారుని సృష్టించడం విఫలమైంది: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, fuzzy, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "సమూహంసమూహానికి కొత్త వినియోగదారుని జోడించడంలో విఫలమైంది: {లోపం {group} {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "అధీకృత SSH కీలు" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7554,36 +7554,36 @@ msgstr "" "అవ్వడానికి అనుమతిస్తుంది. మీరు బహుళ కీలను నమోదు చేయవచ్చు, ఒక్కో లైన్‌లో ఒకటి. #తో ప్రారంభమయ్యే ఖాళీ " "పంక్తులు మరియు పంక్తులు విస్మరించబడతాయి." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "ఎల్.డి.ఏ.పి వాడుకరి పేరుమార్పులో విఫలం." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "సమూహంలోంచి వినియోగదారుని తొలగించడంలో విఫలం." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "సమూహంలోకి వినియోగదారుని జోడించడంలో విఫలం." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "SSH కీలను సెట్ చేయడం సాధ్యం కాలేదు." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "వినియోగదారు స్థితిని మార్చడంలో విఫలమైంది." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "ఎల్.డి.ఏ.పి వాడుకరి పాస్‌వర్డ్ మార్పిడి విఫలం." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "నిర్వాహక సమూహానికి కొత్త వినియోగదారుని జోడించడంలో విఫలమైంది: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "వాడుకరి ఖాతా సృస్టించబడింది, మీరు లాగిన్ చేయబడ్డారు" @@ -8113,7 +8113,7 @@ msgstr "" "సందర్శకులందరినీ అనుమతించండి. నిరుపయోగం చేయడం వలన వర్డుప్రెస్సు సైట్ లేదా బ్లాగును వీక్షించడానికి " "నిర్వాహకులు మాత్రమే అనుమతిస్తుంది. ప్రారంభ వర్డుప్రెస్సు సెటప్ చేసిన తర్వాత మాత్రమే ప్రారంభించండి." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8132,7 +8132,7 @@ msgstr "" "వీక్షణలను ఉపయోగించి ఒక వ్యక్తిని కలిగి ఉన్న అన్ని ఫోటోలు లేదా తేదీలో తీసిన ఫోటోలు లేదా ఒక ప్రదేశంలో తీసిన " "ఫోటోలను కనుగొనడం సులభం. డైరెక్ట్ లింక్‌ని పంపడం ద్వారా వ్యక్తిగత ఫోటోలను ఇతరులతో పంచుకోవచ్చు." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8142,11 +8142,11 @@ msgstr "" "జోఫ్ని సెటప్ చేసిన {box_name} వినియోగదారు కూడా Zophలో నిర్వాహకులు అవుతారు. అదనపు వినియోగదారుల " "కోసం, ఖాతాలు తప్పనిసరిగా {box_name}లో మరియు జోఫ్లో ఒకే వినియోగదారు పేరుతో సృష్టించబడాలి." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "జోఫ్" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "ఫోటో ఆర్గనైజర్" @@ -8203,103 +8203,103 @@ msgstr "సేవ నిలిపివేయబడింది: {name}" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "ప్యాకేజీ {package_name} తాజా వెర్షన్ ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "వ్యవస్థాపిస్తోంది" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "దిగుమతి అవుతోంది" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "ప్రసార మాధ్యమం మార్పు" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "ఆకృతీకరణ ఫైలు: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "ప్యాకేజీ మేనేజర్ కోసం వేచి ఉన్న సమయం ముగిసింది" -#: setup.py:41 +#: setup.py:39 #, fuzzy #| msgid "Install Apps" msgid "Installing app" msgstr "అనువర్తనాలను నిక్షిప్తం చేద్దాం" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "అనువర్తనం నవీకరించబడుతున్నది" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {string}{details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {string}{details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "అనువర్తనం స్థాపించబడింది." -#: setup.py:89 +#: setup.py:96 #, fuzzy #| msgid "Last update" msgid "App updated" msgstr "చివరి నవీకరణ" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Install Apps" msgid "Uninstalling app" msgstr "అనువర్తనాలను నిక్షిప్తం చేద్దాం" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {string}{details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "అనువర్తనం స్థాపించుటలో దోషం: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "అనువర్తనం స్థాపించబడింది." -#: setup.py:453 +#: setup.py:513 #, fuzzy #| msgid "Upgrade Packages" msgid "Updating app packages" @@ -8693,11 +8693,11 @@ msgid "" "installed freshly again." msgstr "మొత్తం యాప్ డేటా మరియు కాన్ఫిగరేషన్ శాశ్వతంగా పోతాయి. యాప్ను మళ్లీ తాజాగా ఇన్‌స్టాల్ చేయవచ్చు." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "మారకుండా అమర్చుతోంది" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "{app_id} ని అన్ఇన్‌స్టాల్ చేయడానికి ముందు" diff --git a/plinth/locale/tr/LC_MESSAGES/django.po b/plinth/locale/tr/LC_MESSAGES/django.po index cf940932a..d8347a7bf 100644 --- a/plinth/locale/tr/LC_MESSAGES/django.po +++ b/plinth/locale/tr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-01-31 05:01+0000\n" "Last-Translator: Burak Yavuz \n" "Language-Team: Turkish https://www.privoxy.org adresinde " "görebilirsiniz." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Web Vekil Sunucusu" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Tcp{kind} üzerinde {proxy} vekil sunucusu ile {url} adresine erişin" @@ -7091,7 +7091,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Dosya Eşitleme" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7262,7 +7262,7 @@ msgstr "Yapılandırma güncelleniyor" msgid "Error configuring app: {error}" msgstr "Uygulama yapılandırılırken hata oldu: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7275,20 +7275,20 @@ msgstr "" "ağı aracılığıyla internete erişmek için çeşitli uygulamalar tarafından " "kullanılabilir. İSS sansürü yukarı akış köprüleri kullanılarak atlatılabilir." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Tor Vekil Sunucusu" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Tor Socks Vekil Sunucusu" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Tor aracılığıyla tcp{kind} üzerinde erişim URL'si {url}" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Tcp{kind} üzerinde {url} adresinde Tor kullanımını onaylama" @@ -7693,7 +7693,7 @@ msgstr "Sık yapılan özellik güncellemeleri etkinleştirildi." msgid "Starting distribution upgrade test." msgstr "Dağıtım yükseltmesi denemesi başlatılıyor." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7704,7 +7704,7 @@ msgstr "" "kullanıcıya, uygulamaya erişme yetkisi vermek için bir kullanıcı hesabının " "bir grubun parçası olmasını gerektirir." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7716,25 +7716,25 @@ msgstr "" "sadece admin grubunun kullanıcıları uygulamaları veya sistem " "ayarlarını değiştirebilir." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Kullanıcılar ve Gruplar" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Tüm hizmetlere ve sistem ayarlarına erişim" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "LDAP \"{search_item}\" girişini denetleme" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "\"{key} {value}\" nslcd yapılandırmasını denetleme" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "\"{database}\" nsswitch yapılandırmasını denetleme" @@ -7743,34 +7743,7 @@ msgstr "\"{database}\" nsswitch yapılandırmasını denetleme" msgid "Username is taken or is reserved." msgstr "Kullanıcı adı alınmış veya ayrılmış." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Geçerli bir kullanıcı adı girin." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Zorunlu. 150 veya daha az karakter. Sadece İngilizce harfler, rakamlar ve " -"@/./-/_ karakterleri." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Yetkilendirme Parolası" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Hesap değişikliklerini yetkilendirmek için \"{user}\" kullanıcısının " -"parolasını girin." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Geçersiz parola." - -#: modules/users/forms.py:112 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 " @@ -7784,21 +7757,48 @@ msgstr "" "kullanıcılar tüm hizmetlere oturum açabilecektir. Ayrıca SSH aracılığıyla " "sisteme oturum açabilir ve yönetici yetkilerine (sudo) sahip olabilirler." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Geçerli bir kullanıcı adı girin." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Zorunlu. 150 veya daha az karakter. Sadece İngilizce harfler, rakamlar ve " +"@/./-/_ karakterleri." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Yetkilendirme Parolası" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Hesap değişikliklerini yetkilendirmek için \"{user}\" kullanıcısının " +"parolasını girin." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Geçersiz parola." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "LDAP kullanıcısı oluşturma başarısız oldu: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "{group} grubuna yeni kullanıcı ekleme başarısız oldu: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Yetkili SSH Anahtarları" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7809,36 +7809,36 @@ msgstr "" "tane olmak üzere birden çok anahtar girebilirsiniz. Boş satırlar ve # ile " "başlayan satırlar yoksayılacaktır." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "LDAP kullanıcısının yeniden adlandırılması başarısız oldu." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Kullanıcıyı gruptan kaldırma başarısız oldu." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Kullanıcıyı gruba ekleme başarısız oldu." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "SSH anahtarları ayarlanamıyor." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Kullanıcı durumunu değiştirme başarısız oldu." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "LDAP kullanıcı parolasının değiştirilmesi başarısız oldu." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Admin grubuna yeni kullanıcı ekleme başarısız oldu: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Kullanıcı hesabı oluşturuldu, şu an oturum açtınız" @@ -8375,7 +8375,7 @@ msgstr "" "WordPress sitesini veya blogunu görüntülemesine izin verir. Sadece ilk " "WordPress kurulumunu gerçekleştirdikten sonra etkinleştirin." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8397,7 +8397,7 @@ msgstr "" "çekilmiş fotoğrafları bulmak kolaydır. Tek tek fotoğraflar, doğrudan bir " "bağlantı gönderilerek başkalarıyla paylaşılabilir." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8408,11 +8408,11 @@ msgstr "" "Ek kullanıcılar için hesaplar hem {box_name} cihazında hem de Zoph'da aynı " "kullanıcı adıyla oluşturulmak zorundadır." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Fotoğraf Düzenleyici" @@ -8470,87 +8470,87 @@ msgstr "Tamamlandı: {name}" msgid "Package {package_expression} is not available for install" msgstr "{package_expression} paketi yükleme için mevcut değil" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "{package_name} paketi en son sürümdür ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "yükleniyor" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "indiriliyor" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "ortam değiştirme" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "yapılandırma dosyası: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Paket yöneticisini beklerken zaman aşımı oldu" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Uygulama yükleniyor" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Uygulama güncelleniyor" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Uygulama yüklenirken hata oldu: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Uygulama güncellenirken hata oldu: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Uygulama yüklenirken hata oldu: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Uygulama güncellenirken hata oldu: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "Uygulama yüklendi." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Uygulama güncellendi" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Uygulama kaldırılıyor" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Uygulama kaldırılırken hata oldu: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Uygulama kaldırılırken hata oldu: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Uygulama kaldırıldı." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Uygulama paketleri güncelleniyor" @@ -8943,11 +8943,11 @@ msgstr "" "Tüm uygulama verileri ve yapılandırması kalıcı olarak kaybolacaktır. " "Uygulama tekrar yeni olarak yüklenebilir." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Ayar değişmedi" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "{app_id} kaldırılmadan önce" diff --git a/plinth/locale/uk/LC_MESSAGES/django.po b/plinth/locale/uk/LC_MESSAGES/django.po index 5121859c7..ccb06bf3f 100644 --- a/plinth/locale/uk/LC_MESSAGES/django.po +++ b/plinth/locale/uk/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-02-05 00:01+0000\n" "Last-Translator: Ihor Hordiichuk \n" "Language-Team: Ukrainian . Передача відбувається через мережу Tor для додаткової анонімності, " "якщо у вас увімкнено програму Tor." -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5600,7 +5600,7 @@ msgstr "" "підвищення приватності, зміни даних вебсторінок і HTTP-заголовків, контролю " "доступу, а також видалення реклами та іншого небажаного інтернет-мотлоху. " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5617,15 +5617,15 @@ msgstr "" "посиланнями http://config.privoxy.org/" " або http://p.p." -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Вебпроксі" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "Доступ за адресою {url} через проксі {proxy} по tcp{kind}" @@ -7090,7 +7090,7 @@ msgstr "Syncthing" msgid "File Synchronization" msgstr "Синхронізація файлів" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -7260,7 +7260,7 @@ msgstr "Оновлення налаштувань" msgid "Error configuring app: {error}" msgstr "Помилка налаштування застосунку: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -7273,20 +7273,20 @@ msgstr "" "різними застосунками для доступу до інтернету через мережу Tor. Цензурування " "постачальником послуг інтернету може бути обійдене за допомогою мостів." -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Проксі Tor" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "Проксі Tor Socks" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "Доступ за адресою {url} на tcp{kind} через Tor" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "Підтвердити використання Tor можна за посиланням {url} на tcp{kind}" @@ -7687,7 +7687,7 @@ msgstr "Оновлення частих можливостей активова msgid "Starting distribution upgrade test." msgstr "Запуск тесту оновлення дистрибутиву." -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " @@ -7698,7 +7698,7 @@ msgstr "" "застосунки також вимагають, щоб обліковий запис був частиною групи, щоб " "отримати авторизований доступ до застосунку." -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -7710,25 +7710,25 @@ msgstr "" "користувачі з групи admin можуть змінювати застосунки або системні " "налаштування." -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "Користувачі і групи" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "Доступ до всіх сервісів і налаштувань системи" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "Перевірка запису LDAP \"{search_item}\"" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "Перевірте nslcd конфігурацію \"{key} {value}\"" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "Перевірте nsswitch конфігурацію \"{database}\"" @@ -7737,33 +7737,7 @@ msgstr "Перевірте nsswitch конфігурацію \"{database}\"" msgid "Username is taken or is reserved." msgstr "Імʼя користувача зайняте або зарезервоване." -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "Уведіть коректне імʼя користувача." - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" -"Обовʼязково. 150 знаків, не більше. Лише англійські букви, цифри і @/./-/_." - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "Пароль для авторизації" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" -"Уведіть пароль для користувача \"{user}\", щоб авторизувати зміни облікового " -"запису." - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "Неправильний пароль." - -#: modules/users/forms.py:112 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 " @@ -7777,21 +7751,47 @@ msgstr "" "входити в усі сервіси. Вони також можуть входити в систему через SSH і мати " "адміністративні права (sudo)." -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "Уведіть коректне імʼя користувача." + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" +"Обовʼязково. 150 знаків, не більше. Лише англійські букви, цифри і @/./-/_." + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "Пароль для авторизації" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" +"Уведіть пароль для користувача \"{user}\", щоб авторизувати зміни облікового " +"запису." + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "Неправильний пароль." + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "Не вдалося створити користувача LDAP: {error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "Не вдалося додати нового користувача до групи {group}: {error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "Ключі SSH для авторизації" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7801,36 +7801,36 @@ msgstr "" "систему без використання пароля. Ви можете вказати декілька ключів, один на " "кожен рядок. Порожні рядки і рядки, що починаються на # іґноруються." -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "Не вдалося перейменувати користувача LDAP." -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "Не вдалося вилучити користувача з групи." -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "Не вдалося додати користувача до групи." -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "Не можливо задати ключі SSH." -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "Не вдалося змінити стан користувача." -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "Не вдалося змінити пароль користувача LDAP." -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "Не вдалося додати нового користувача до адмінської групи: {error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "Обліковий запис користувача створено, Ви ввійшли в систему" @@ -8367,7 +8367,7 @@ msgstr "" "переглядати сайт або блог WordPress. Увімкнути тільки після виконання " "початкового налаштування WordPress." -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -8389,7 +8389,7 @@ msgstr "" "календарного перегляду. Окремими світлинами можна ділитися з іншими, " "надіславши пряме посилання." -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -8400,11 +8400,11 @@ msgstr "" "Для додаткових користувачів потрібно створити облікові записи і в " "{box_name}, і в Zoph з тим же іменем користувача." -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "Zoph" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "Упорядник світлин" @@ -8462,87 +8462,87 @@ msgstr "Завершено: {name}" msgid "Package {package_expression} is not available for install" msgstr "Пакунок {package_expression} недоступний для встановлення" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "Пакунок {package_name} має останню версію ({latest_version})" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "встановлення" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "завантаження" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "зміна медія" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "файл конфіґурації: {file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "Час очікування менеджера пакунків" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "Встановлення застосунку" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "Оновлення застосунку" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "Помилка встановлення застосунку: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "Помилка оновлення застосунку: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "Помилка встановлення застосунку: {error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "Помилка оновлення застосунку: {error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "Застосунок встановлено." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "Застосунок оновлено" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "Видалення застосунку" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "Помилка видалення застосунку: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "Помилка видалення застосунку: {error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "Застосунок видалено." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "Оновлення пакунків застосунків" @@ -8935,11 +8935,11 @@ msgstr "" "Усі дані програми та налаштування буде втрачено назавжди. Застосунок можна " "встановити начисто ще раз." -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "Налаштування не змінено" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "перед видаленням {app_id}" diff --git a/plinth/locale/vi/LC_MESSAGES/django.po b/plinth/locale/vi/LC_MESSAGES/django.po index 448c5e147..35fe7998e 100644 --- a/plinth/locale/vi/LC_MESSAGES/django.po +++ b/plinth/locale/vi/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2021-07-28 08:34+0000\n" "Last-Translator: bruh \n" "Language-Team: Vietnamese http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6438,7 +6438,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6583,7 +6583,7 @@ msgstr "Đã xảy ra lỗi trong khi thiết lập." msgid "Error configuring app: {error}" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6592,20 +6592,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6953,14 +6953,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6968,25 +6968,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6995,30 +6995,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -7027,57 +7004,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7559,7 +7559,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7572,7 +7572,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7580,11 +7580,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7639,99 +7639,99 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "Lỗi khi cài đặt ứng dụng: {string} {details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "Lỗi khi cài đặt ứng dụng: {string} {details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "Ứng dụng đã được cài đặt." -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "Lỗi khi cài đặt ứng dụng: {string} {details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "Lỗi khi cài đặt ứng dụng: {error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "Ứng dụng đã được cài đặt." -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -8093,11 +8093,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/zh_Hans/LC_MESSAGES/django.po b/plinth/locale/zh_Hans/LC_MESSAGES/django.po index ece3474ca..224b9e07b 100644 --- a/plinth/locale/zh_Hans/LC_MESSAGES/django.po +++ b/plinth/locale/zh_Hans/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Plinth\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2024-01-31 05:01+0000\n" "Last-Translator: 大王叫我来巡山 \n" @@ -29,27 +29,27 @@ msgstr "" msgid "FreedomBox" msgstr "FreedomBox" -#: daemon.py:105 +#: daemon.py:122 #, python-brace-format msgid "Service {service_name} is running" msgstr "服务{service_name}正在运行" -#: daemon.py:164 +#: daemon.py:218 #, python-brace-format msgid "Listening on {kind} port {listen_address}:{port}" msgstr "正在侦听 {kind} 端口 {listen_address}:{port}" -#: daemon.py:167 +#: daemon.py:221 #, python-brace-format msgid "Listening on {kind} port {port}" msgstr "正在侦听 {kind} 端口 {port}" -#: daemon.py:236 +#: daemon.py:291 #, python-brace-format msgid "Connect to {host}:{port}" msgstr "连接到主机 {host}:{port}" -#: daemon.py:240 +#: daemon.py:299 #, python-brace-format msgid "Cannot connect to {host}:{port}" msgstr "不能连接到主机 {host}:{port}" @@ -115,12 +115,12 @@ msgstr "Web 服务器" msgid "{box_name} Web Interface (Plinth)" msgstr "{box_name} Web 界面(Plinth)" -#: modules/apache/components.py:154 +#: modules/apache/components.py:159 #, python-brace-format msgid "Access URL {url} on tcp{kind}" msgstr "在 tcp {kind} 访问 URL {url}" -#: modules/apache/components.py:157 +#: modules/apache/components.py:162 #, python-brace-format msgid "Access URL {url}" msgstr "访问 URL {url}" @@ -783,7 +783,7 @@ msgid "Permissions for anonymous users, who have not provided a password." msgstr "未提供密码的匿名用户的权限。" #: modules/bepasty/forms.py:27 modules/bepasty/templates/bepasty.html:30 -#: modules/users/forms.py:110 modules/users/forms.py:233 +#: modules/users/forms.py:91 msgid "Permissions" msgstr "许可" @@ -1388,54 +1388,54 @@ msgstr "下载目录" msgid "Bittorrent client written in Python/PyGTK" msgstr "用Python/PyGTK编写的Bittorrent客户端" -#: modules/diagnostics/__init__.py:27 +#: modules/diagnostics/__init__.py:28 msgid "" "The system diagnostic test will run a number of checks on your system to " "confirm that applications and services are working as expected." msgstr "" "系统诊断将运行测试程序检查您的系统以确认应用程序和服务正在按预期方式运行。" -#: modules/diagnostics/__init__.py:51 modules/diagnostics/__init__.py:236 +#: modules/diagnostics/__init__.py:52 modules/diagnostics/__init__.py:238 msgid "Diagnostics" msgstr "诊断程序" -#: modules/diagnostics/__init__.py:95 +#: modules/diagnostics/__init__.py:96 msgid "passed" msgstr "通过了" -#: modules/diagnostics/__init__.py:96 modules/networks/views.py:50 +#: modules/diagnostics/__init__.py:97 modules/networks/views.py:50 msgid "failed" msgstr "失败" -#: modules/diagnostics/__init__.py:97 +#: modules/diagnostics/__init__.py:98 msgid "error" msgstr "错误" -#: modules/diagnostics/__init__.py:98 +#: modules/diagnostics/__init__.py:99 msgid "warning" msgstr "警告" #. Translators: This is the unit of computer storage Mebibyte similar to #. Megabyte. -#: modules/diagnostics/__init__.py:202 +#: modules/diagnostics/__init__.py:204 msgid "MiB" msgstr "MiB" #. Translators: This is the unit of computer storage Gibibyte similar to #. Gigabyte. -#: modules/diagnostics/__init__.py:207 +#: modules/diagnostics/__init__.py:209 msgid "GiB" msgstr "GiB" -#: modules/diagnostics/__init__.py:214 +#: modules/diagnostics/__init__.py:216 msgid "You should disable some apps to reduce memory usage." msgstr "你应该禁用一些应用程序以减少内存的使用。" -#: modules/diagnostics/__init__.py:219 +#: modules/diagnostics/__init__.py:221 msgid "You should not install any new apps on this system." msgstr "你不应该在这个系统上安装任何新的应用程序。" -#: modules/diagnostics/__init__.py:231 +#: modules/diagnostics/__init__.py:233 #, no-python-format, python-brace-format msgid "" "System is low on memory: {percent_used}% used, {memory_available} " @@ -1444,24 +1444,24 @@ msgstr "" "系统内存不足:已使用 {percent_used},{memory_available} " "{memory_available_unit}可用。{advice_message}" -#: modules/diagnostics/__init__.py:233 +#: modules/diagnostics/__init__.py:235 msgid "Low Memory" msgstr "低内存" -#: modules/diagnostics/__init__.py:264 +#: modules/diagnostics/__init__.py:266 msgid "Running diagnostics" msgstr "运行诊断程序" -#: modules/diagnostics/__init__.py:307 +#: modules/diagnostics/__init__.py:309 #, no-python-format, python-brace-format msgid "Found {issue_count} issues during routine tests." msgstr "" -#: modules/diagnostics/__init__.py:308 +#: modules/diagnostics/__init__.py:310 msgid "Diagnostics results" msgstr "诊断结果" -#: modules/diagnostics/__init__.py:313 +#: modules/diagnostics/__init__.py:315 msgid "Go to diagnostics results" msgstr "转到诊断结果" @@ -1540,7 +1540,7 @@ msgstr "测试" msgid "Result" msgstr "结果" -#: modules/diagnostics/views.py:107 +#: modules/diagnostics/views.py:111 msgid "Diagnostic Test" msgstr "诊断测试" @@ -1684,7 +1684,7 @@ msgid "Use HTTP basic authentication" msgstr "使用 HTTP 基本身份验证" #: modules/dynamicdns/forms.py:88 modules/networks/forms.py:207 -#: modules/users/forms.py:67 +#: modules/users/forms.py:117 msgid "Username" msgstr "用户名" @@ -2070,29 +2070,29 @@ msgstr "" msgid "Firewall" msgstr "防火墙" -#: modules/firewall/__init__.py:271 +#: modules/firewall/__init__.py:272 msgid "Default zone is external" msgstr "默认区域是外部的" -#: modules/firewall/__init__.py:280 +#: modules/firewall/__init__.py:282 msgid "Firewall backend is nftables" msgstr "" -#: modules/firewall/__init__.py:293 +#: modules/firewall/__init__.py:296 msgid "Direct passthrough rules exist" msgstr "" -#: modules/firewall/components.py:136 +#: modules/firewall/components.py:139 #, python-brace-format msgid "Port {name} ({details}) available for internal networks" msgstr "内网端口 {name}({details})可用" -#: modules/firewall/components.py:147 +#: modules/firewall/components.py:153 #, python-brace-format msgid "Port {name} ({details}) available for external networks" msgstr "外网端口 {name}({details})可用" -#: modules/firewall/components.py:153 +#: modules/firewall/components.py:159 #, python-brace-format msgid "Port {name} ({details}) unavailable for external networks" msgstr "" @@ -2212,11 +2212,11 @@ msgstr "" msgid "Read-write access to Git repositories" msgstr "" -#: modules/gitweb/__init__.py:50 modules/gitweb/manifest.py:11 +#: modules/gitweb/__init__.py:48 modules/gitweb/manifest.py:11 msgid "Gitweb" msgstr "" -#: modules/gitweb/__init__.py:51 +#: modules/gitweb/__init__.py:49 msgid "Simple Git Hosting" msgstr "" @@ -2681,7 +2681,7 @@ msgid "I2P" msgstr "" #: modules/i2p/__init__.py:53 modules/tor/__init__.py:63 -#: modules/torproxy/__init__.py:56 +#: modules/torproxy/__init__.py:57 msgid "Anonymity Network" msgstr "匿名网络" @@ -3660,19 +3660,19 @@ msgstr "安全 Shell" msgid "Services" msgstr "服务" -#: modules/networks/__init__.py:35 +#: modules/networks/__init__.py:36 msgid "" "Configure network devices. Connect to the Internet via Ethernet, Wi-Fi or " "PPPoE. Share that connection with other devices on the network." msgstr "" -#: modules/networks/__init__.py:37 +#: modules/networks/__init__.py:38 msgid "" "Devices administered through other methods may not be available for " "configuration here." msgstr "" -#: modules/networks/__init__.py:58 +#: modules/networks/__init__.py:59 msgid "Networks" msgstr "网络" @@ -5069,7 +5069,7 @@ msgid "" "network for additional anonymity if Tor app is enabled." msgstr "" -#: modules/privoxy/__init__.py:24 +#: modules/privoxy/__init__.py:25 msgid "" "Privoxy is a non-caching web proxy with advanced filtering capabilities for " "enhancing privacy, modifying web page data and HTTP headers, controlling " @@ -5078,7 +5078,7 @@ msgstr "" "Privoxy 是一个非缓存 Web 代理,具有高级过滤功能,用于增强隐私,修改网页数据" "和 HTTP 标头,控制访问,以及删除广告和其他令人讨厌的互联网垃圾。 " -#: modules/privoxy/__init__.py:29 +#: modules/privoxy/__init__.py:30 #, python-brace-format msgid "" "You can use Privoxy by modifying your browser proxy settings to your " @@ -5093,15 +5093,15 @@ msgstr "" "config.privoxy.org\">http://config.privoxy.org/ 或 http://p.p 中查看其配置详细信息和文档。" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "Privoxy" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "Web 代理" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "在 tcp{kind} 上通过 {proxy} 访问 {url}" @@ -6398,7 +6398,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6550,7 +6550,7 @@ msgstr "更新配置" msgid "Error configuring app: {error}" msgstr "配置应用出错:{error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6559,20 +6559,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "Tor 代理" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "在 tcp{kind} 上通过 Tor 访问 {url}" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "确认使用 Tor 通过 tcp{kind} 访问 {url}" @@ -6925,14 +6925,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "启动分发升级测试。" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6940,25 +6940,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "用户和组" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "请检查 LDAP 条目“{search_item}”" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6967,30 +6967,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "用户名已经占用或保留。" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "输入有效的用户名。" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "验证密码" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "密码无效。" - -#: modules/users/forms.py:112 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 " @@ -7002,21 +6979,44 @@ msgstr "" "单点登录的服务。

管理员(admin)组中的用户将能够登录所有服务。他们还可" "以通过 SSH 登录到系统并具有管理权限(sudo)。" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "输入有效的用户名。" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "验证密码" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "密码无效。" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "创建 LDAP 用户失败:{error}" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "未能将新用户添加到 {group} 组:{error}" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " @@ -7025,36 +7025,36 @@ msgstr "" "设置 SSH 公钥将允许此用户安全地登录到系统不使用密码。您可以输入多个密钥,每行" "一个。将忽略空行和以 # 开头的行。" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "重命名 LDAP 用户失败。" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "无法从组中删除用户。" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "无法将用户添加到组。" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "不能设置 SSH 密钥。" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "更改用户状态失败。" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "更改 LDAP 用户密码失败。" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "未能将新用户添加到管理员组:{error}" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "用户帐户已创建,您现在可以登录" @@ -7538,7 +7538,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7551,7 +7551,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7559,11 +7559,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7617,87 +7617,87 @@ msgstr "已完成:{name}" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "安装" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "下载中" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "媒体改变" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "配置文件:{file}" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "安装应用中" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, python-brace-format msgid "Error installing app: {string} {details}" msgstr "安装应用出错:{string} {details}" -#: setup.py:74 +#: setup.py:81 #, python-brace-format msgid "Error updating app: {string} {details}" msgstr "更新应用出错:{string} {details}" -#: setup.py:80 +#: setup.py:87 #, python-brace-format msgid "Error installing app: {error}" msgstr "安装应用出错:{error}" -#: setup.py:83 +#: setup.py:90 #, python-brace-format msgid "Error updating app: {error}" msgstr "更新应用出错:{error}" -#: setup.py:87 +#: setup.py:94 msgid "App installed." msgstr "应用已安装。" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "应用已更新" -#: setup.py:106 +#: setup.py:113 msgid "Uninstalling app" msgstr "卸载应用" -#: setup.py:124 +#: setup.py:131 #, python-brace-format msgid "Error uninstalling app: {string} {details}" msgstr "卸载应用出错:{string} {details}" -#: setup.py:130 +#: setup.py:137 #, python-brace-format msgid "Error uninstalling app: {error}" msgstr "卸载应用出错:{error}" -#: setup.py:133 +#: setup.py:140 msgid "App uninstalled." msgstr "应用已卸载。" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "更新软件包中" @@ -8064,11 +8064,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "设置未改变" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" diff --git a/plinth/locale/zh_Hant/LC_MESSAGES/django.po b/plinth/locale/zh_Hant/LC_MESSAGES/django.po index 791202e34..95e4af111 100644 --- a/plinth/locale/zh_Hant/LC_MESSAGES/django.po +++ b/plinth/locale/zh_Hant/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-12 20:35-0500\n" +"POT-Creation-Date: 2024-03-11 20:10-0400\n" "PO-Revision-Date: 2021-12-23 12:50+0000\n" "Last-Translator: pesder \n" "Language-Team: Chinese (Traditional) http://p.p." msgstr "" -#: modules/privoxy/__init__.py:52 +#: modules/privoxy/__init__.py:53 msgid "Privoxy" msgstr "" -#: modules/privoxy/__init__.py:53 +#: modules/privoxy/__init__.py:54 msgid "Web Proxy" msgstr "" -#: modules/privoxy/__init__.py:117 +#: modules/privoxy/__init__.py:118 #, python-brace-format msgid "Access {url} with proxy {proxy} on tcp{kind}" msgstr "" @@ -6292,7 +6292,7 @@ msgstr "" msgid "File Synchronization" msgstr "" -#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:28 +#: modules/tor/__init__.py:33 modules/torproxy/__init__.py:29 msgid "" "Tor is an anonymous communication system. You can learn more about it from " "the Tor Project website. For " @@ -6437,7 +6437,7 @@ msgstr "設置過程中發生錯誤。" msgid "Error configuring app: {error}" msgstr "安裝應用遇到錯誤:{error}" -#: modules/torproxy/__init__.py:35 +#: modules/torproxy/__init__.py:36 #, python-brace-format msgid "" "This app provides a web proxy on your {box_name} for internal networks on " @@ -6446,20 +6446,20 @@ msgid "" "using upstream bridges." msgstr "" -#: modules/torproxy/__init__.py:55 +#: modules/torproxy/__init__.py:56 msgid "Tor Proxy" msgstr "" -#: modules/torproxy/__init__.py:80 +#: modules/torproxy/__init__.py:81 msgid "Tor Socks Proxy" msgstr "" -#: modules/torproxy/__init__.py:140 +#: modules/torproxy/__init__.py:142 #, python-brace-format msgid "Access URL {url} on tcp{kind} via Tor" msgstr "" -#: modules/torproxy/__init__.py:152 +#: modules/torproxy/__init__.py:154 #, python-brace-format msgid "Confirm Tor usage at {url} on tcp{kind}" msgstr "" @@ -6807,14 +6807,14 @@ msgstr "" msgid "Starting distribution upgrade test." msgstr "" -#: modules/users/__init__.py:32 +#: modules/users/__init__.py:33 msgid "" "Create and manage user accounts. These accounts serve as centralized " "authentication mechanism for most apps. Some apps further require a user " "account to be part of a group to authorize the user to access the app." msgstr "" -#: modules/users/__init__.py:37 +#: modules/users/__init__.py:38 #, python-brace-format msgid "" "Any user may login to {box_name} web interface to see a list of apps " @@ -6822,25 +6822,25 @@ msgid "" "group may alter apps or system settings." msgstr "" -#: modules/users/__init__.py:58 +#: modules/users/__init__.py:59 msgid "Users and Groups" msgstr "" -#: modules/users/__init__.py:83 +#: modules/users/__init__.py:84 msgid "Access to all services and system settings" msgstr "" -#: modules/users/__init__.py:127 +#: modules/users/__init__.py:128 #, python-brace-format msgid "Check LDAP entry \"{search_item}\"" msgstr "" -#: modules/users/__init__.py:141 +#: modules/users/__init__.py:143 #, python-brace-format msgid "Check nslcd config \"{key} {value}\"" msgstr "" -#: modules/users/__init__.py:171 +#: modules/users/__init__.py:173 #, python-brace-format msgid "Check nsswitch config \"{database}\"" msgstr "" @@ -6849,30 +6849,7 @@ msgstr "" msgid "Username is taken or is reserved." msgstr "" -#: modules/users/forms.py:62 -msgid "Enter a valid username." -msgstr "" - -#: modules/users/forms.py:69 -msgid "" -"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." -msgstr "" - -#: modules/users/forms.py:78 -msgid "Authorization Password" -msgstr "" - -#: modules/users/forms.py:85 -#, python-brace-format -msgid "" -"Enter the password for user \"{user}\" to authorize account modifications." -msgstr "" - #: modules/users/forms.py:94 -msgid "Invalid password." -msgstr "" - -#: modules/users/forms.py:112 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 " @@ -6881,57 +6858,80 @@ msgid "" "SSH and have administrative privileges (sudo)." msgstr "" -#: modules/users/forms.py:155 modules/users/forms.py:375 +#: modules/users/forms.py:112 +msgid "Enter a valid username." +msgstr "" + +#: modules/users/forms.py:119 +msgid "" +"Required. 150 characters or fewer. English letters, digits and @/./-/_ only." +msgstr "" + +#: modules/users/forms.py:128 +msgid "Authorization Password" +msgstr "" + +#: modules/users/forms.py:135 +#, python-brace-format +msgid "" +"Enter the password for user \"{user}\" to authorize account modifications." +msgstr "" + +#: modules/users/forms.py:144 +msgid "Invalid password." +msgstr "" + +#: modules/users/forms.py:200 modules/users/forms.py:398 #, python-brace-format msgid "Creating LDAP user failed: {error}" msgstr "" -#: modules/users/forms.py:166 +#: modules/users/forms.py:212 #, python-brace-format msgid "Failed to add new user to {group} group: {error}" msgstr "" -#: modules/users/forms.py:181 +#: modules/users/forms.py:228 msgid "Authorized SSH Keys" msgstr "" -#: modules/users/forms.py:183 +#: modules/users/forms.py:230 msgid "" "Setting an SSH public key will allow this user to securely log in to the " "system without using a password. You may enter multiple keys, one on each " "line. Blank lines and lines starting with # will be ignored." msgstr "" -#: modules/users/forms.py:263 +#: modules/users/forms.py:286 msgid "Renaming LDAP user failed." msgstr "" -#: modules/users/forms.py:274 +#: modules/users/forms.py:297 msgid "Failed to remove user from group." msgstr "" -#: modules/users/forms.py:284 +#: modules/users/forms.py:307 msgid "Failed to add user to group." msgstr "" -#: modules/users/forms.py:291 +#: modules/users/forms.py:314 msgid "Unable to set SSH keys." msgstr "" -#: modules/users/forms.py:304 +#: modules/users/forms.py:327 msgid "Failed to change user status." msgstr "" -#: modules/users/forms.py:345 +#: modules/users/forms.py:368 msgid "Changing LDAP user password failed." msgstr "" -#: modules/users/forms.py:383 +#: modules/users/forms.py:406 #, python-brace-format msgid "Failed to add new user to admin group: {error}" msgstr "" -#: modules/users/forms.py:408 +#: modules/users/forms.py:429 msgid "User account created, you are now logged in" msgstr "" @@ -7413,7 +7413,7 @@ msgid "" "WordPress site or blog. Enable only after performing initial WordPress setup." msgstr "" -#: modules/zoph/__init__.py:23 +#: modules/zoph/__init__.py:24 #, python-brace-format msgid "" "Zoph manages your photo collection. Photos are stored on your {box_name}, " @@ -7426,7 +7426,7 @@ msgid "" "shared with others by sending a direct link." msgstr "" -#: modules/zoph/__init__.py:34 +#: modules/zoph/__init__.py:35 #, python-brace-format msgid "" "The {box_name} user who setup Zoph will also become the administrator in " @@ -7434,11 +7434,11 @@ msgid "" "in Zoph with the same user name." msgstr "" -#: modules/zoph/__init__.py:53 modules/zoph/manifest.py:6 +#: modules/zoph/__init__.py:56 modules/zoph/manifest.py:6 msgid "Zoph" msgstr "" -#: modules/zoph/__init__.py:54 +#: modules/zoph/__init__.py:57 msgid "Photo Organizer" msgstr "" @@ -7493,99 +7493,99 @@ msgstr "" msgid "Package {package_expression} is not available for install" msgstr "" -#: package.py:231 +#: package.py:234 #, python-brace-format msgid "Package {package_name} is the latest version ({latest_version})" msgstr "" -#: package.py:382 +#: package.py:385 msgid "installing" msgstr "" -#: package.py:384 +#: package.py:387 msgid "downloading" msgstr "" -#: package.py:386 +#: package.py:389 msgid "media change" msgstr "" -#: package.py:388 +#: package.py:391 #, python-brace-format msgid "configuration file: {file}" msgstr "" -#: package.py:416 package.py:441 +#: package.py:419 package.py:444 msgid "Timeout waiting for package manager" msgstr "" -#: setup.py:41 +#: setup.py:39 msgid "Installing app" msgstr "" -#: setup.py:43 +#: setup.py:41 msgid "Updating app" msgstr "" -#: setup.py:70 +#: setup.py:77 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error installing app: {string} {details}" msgstr "安裝過程中遇到錯誤:{string}{details}" -#: setup.py:74 +#: setup.py:81 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error updating app: {string} {details}" msgstr "安裝過程中遇到錯誤:{string}{details}" -#: setup.py:80 +#: setup.py:87 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error installing app: {error}" msgstr "安裝應用遇到錯誤:{error}" -#: setup.py:83 +#: setup.py:90 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error updating app: {error}" msgstr "安裝應用遇到錯誤:{error}" -#: setup.py:87 +#: setup.py:94 #, fuzzy #| msgid "Application installed." msgid "App installed." msgstr "應用已完成安裝。" -#: setup.py:89 +#: setup.py:96 msgid "App updated" msgstr "" -#: setup.py:106 +#: setup.py:113 #, fuzzy #| msgid "Error installing application: {error}" msgid "Uninstalling app" msgstr "安裝應用遇到錯誤:{error}" -#: setup.py:124 +#: setup.py:131 #, fuzzy, python-brace-format #| msgid "Error installing application: {string} {details}" msgid "Error uninstalling app: {string} {details}" msgstr "安裝過程中遇到錯誤:{string}{details}" -#: setup.py:130 +#: setup.py:137 #, fuzzy, python-brace-format #| msgid "Error installing application: {error}" msgid "Error uninstalling app: {error}" msgstr "安裝應用遇到錯誤:{error}" -#: setup.py:133 +#: setup.py:140 #, fuzzy #| msgid "Application installed." msgid "App uninstalled." msgstr "應用已完成安裝。" -#: setup.py:453 +#: setup.py:513 msgid "Updating app packages" msgstr "" @@ -7944,11 +7944,11 @@ msgid "" "installed freshly again." msgstr "" -#: views.py:242 +#: views.py:247 msgid "Setting unchanged" msgstr "" -#: views.py:479 +#: views.py:481 #, python-brace-format msgid "before uninstall of {app_id}" msgstr "" From d962e8b4c07119f4c969c4180b6d5d7d1c005ffd Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Mon, 11 Mar 2024 20:40:29 -0400 Subject: [PATCH 33/63] doc: Fetch latest manual Signed-off-by: James Valleroy --- doc/manual/en/ReleaseNotes.raw.wiki | 41 +++++++++++++++++++++++++++++ doc/manual/es/ReleaseNotes.raw.wiki | 41 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/doc/manual/en/ReleaseNotes.raw.wiki b/doc/manual/en/ReleaseNotes.raw.wiki index 696ddcd00..11a79fe08 100644 --- a/doc/manual/en/ReleaseNotes.raw.wiki +++ b/doc/manual/en/ReleaseNotes.raw.wiki @@ -8,6 +8,47 @@ For more technical details, see the [[https://salsa.debian.org/freedombox-team/f The following are the release notes for each !FreedomBox version. +== FreedomBox 24.6 (2024-03-11) == + +=== Highlights === + + * gitweb: Fix modifying git repositories when gitweb app is disabled + * users: Fix creating users with initial set of groups + * wordpress: + * Don't fail setup if mysql installed but not running + * Drop database user when app is uninstalled + * Fix backup, restore and uninstall when db is not running + * zoph: + * Don't fail setup if mysql installed but not running + * Don't fail with backup/restore if app is disabled + * Don't redirect to setup page when app is disabled + * Ensure that database server is running when setting up app + * Hide configuration form when app is disabled + * Restore database password to old value after restore operation + * Uninstall fully so that reinstall works + +=== Other Changes === + + * *: Add type hints for app init methods + * *: Add type hints for diagnose method + * action_utils: Implement method for starting a service temporarily + * actions: Fix log message when action return can't be decoded + * actions: When action errors out, log a better message + * app: Add ability to hide configuration form when app is disabled + * app: views: Expose method to get enabled/disabled state and cache it + * daemon: Added method to ensure a daemon is running in component + * diagnostics: Add tests for get_results + * diagnostics: Handle !TypeError when copying results + * locale: Update translations for Dutch + * log: Don't log with in color inside actions scripts + * samba: Ignore non-existent users who are in freedombox-share group + * tests: functional: Refactor install/setup fixture for apps + * tests: functional: Uninstall app after backup and before restore + * users: Minor refactor when creating django groups + * users: tests: Do not remove LDAP user when testing views + * wordpress: Fix minor issue in restoring database + * wordpress: tests: Uninstall app after backup and before restore + == FreedomBox 24.5 (2024-02-26) == * backups: tests: Don't use pytest marks on fixtures diff --git a/doc/manual/es/ReleaseNotes.raw.wiki b/doc/manual/es/ReleaseNotes.raw.wiki index 696ddcd00..11a79fe08 100644 --- a/doc/manual/es/ReleaseNotes.raw.wiki +++ b/doc/manual/es/ReleaseNotes.raw.wiki @@ -8,6 +8,47 @@ For more technical details, see the [[https://salsa.debian.org/freedombox-team/f The following are the release notes for each !FreedomBox version. +== FreedomBox 24.6 (2024-03-11) == + +=== Highlights === + + * gitweb: Fix modifying git repositories when gitweb app is disabled + * users: Fix creating users with initial set of groups + * wordpress: + * Don't fail setup if mysql installed but not running + * Drop database user when app is uninstalled + * Fix backup, restore and uninstall when db is not running + * zoph: + * Don't fail setup if mysql installed but not running + * Don't fail with backup/restore if app is disabled + * Don't redirect to setup page when app is disabled + * Ensure that database server is running when setting up app + * Hide configuration form when app is disabled + * Restore database password to old value after restore operation + * Uninstall fully so that reinstall works + +=== Other Changes === + + * *: Add type hints for app init methods + * *: Add type hints for diagnose method + * action_utils: Implement method for starting a service temporarily + * actions: Fix log message when action return can't be decoded + * actions: When action errors out, log a better message + * app: Add ability to hide configuration form when app is disabled + * app: views: Expose method to get enabled/disabled state and cache it + * daemon: Added method to ensure a daemon is running in component + * diagnostics: Add tests for get_results + * diagnostics: Handle !TypeError when copying results + * locale: Update translations for Dutch + * log: Don't log with in color inside actions scripts + * samba: Ignore non-existent users who are in freedombox-share group + * tests: functional: Refactor install/setup fixture for apps + * tests: functional: Uninstall app after backup and before restore + * users: Minor refactor when creating django groups + * users: tests: Do not remove LDAP user when testing views + * wordpress: Fix minor issue in restoring database + * wordpress: tests: Uninstall app after backup and before restore + == FreedomBox 24.5 (2024-02-26) == * backups: tests: Don't use pytest marks on fixtures From 88c12df7e0ec69ef9c120b117827485b591f58f9 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Mon, 11 Mar 2024 20:41:10 -0400 Subject: [PATCH 34/63] Release v24.6 to unstable Signed-off-by: James Valleroy --- debian/changelog | 45 +++++++++++++++++++++++++++++++++++++++++++++ plinth/__init__.py | 2 +- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index a7c8fc9c4..23074def2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,48 @@ +freedombox (24.6) unstable; urgency=medium + + [ Veiko Aasa ] + * gitweb: Fix modifying git repositories when gitweb app is disabled + * users: tests: Do not remove LDAP user when testing views + * samba: Ignore non-existent users who are in freedombox-share group + + [ ikmaak ] + * Translated using Weblate (Dutch) + + [ James Valleroy ] + * diagnostics: Add tests for get_results + * diagnostics: Handle TypeError when copying results + * locale: Update translation strings + * doc: Fetch latest manual + + [ Sunil Mohan Adapa ] + * users: Fix creating users with initial set of groups + * users: Minor refactor when creating django groups + * log: Don't log with in color inside actions scripts + * actions: Fix log message when action return can't be decoded + * actions: When action errors out, log a better message + * *: Add type hints for app init methods + * *: Add type hints for diagnose method + * action_utils: Implement method for starting a service temporarily + * zoph: Don't fail setup if mysql installed but not running + * wordpress: Don't fail setup if mysql installed but not running + * app: Add ability to hide configuration form when app is disabled + * zoph: Hide configuration form when app is disabled + * app: views: Expose method to get enabled/disabled state and cache it + * zoph: Don't redirect to setup page when app is disabled + * zoph: Don't fail with backup/restore if app is disabled + * zoph: Uninstall fully so that reinstall works + * daemon: Added method to ensure a daemon is running in component + * zoph: Ensure that database server is running when setting up app + * wordpress: Fix backup, restore and uninstall when db is not running + * wordpress: Drop database user when app is uninstalled + * tests: functional: Uninstall app after backup and before restore + * zoph: Restore database password to old value after restore operation + * wordpress: tests: Uninstall app after backup and before restore + * tests: functional: Refactor install/setup fixture for apps + * wordpress: Fix minor issue in restoring database + + -- James Valleroy Mon, 11 Mar 2024 20:40:48 -0400 + freedombox (24.5) unstable; urgency=medium [ Sunil Mohan Adapa ] diff --git a/plinth/__init__.py b/plinth/__init__.py index 5ccd68a0b..8e06a2034 100644 --- a/plinth/__init__.py +++ b/plinth/__init__.py @@ -3,4 +3,4 @@ Package init file. """ -__version__ = '24.5' +__version__ = '24.6' From ac7ef9e5c40e5026625b0b68c48e440dfb67f261 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sun, 10 Mar 2024 11:38:20 -0700 Subject: [PATCH 35/63] actions: Move most of the privileged action code to main directory Tests - Run unit tests. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- actions/actions | 207 +-------------------------- plinth/actions.py | 196 ++++++++++++++++++++++++- plinth/tests/test_actions_actions.py | 19 ++- 3 files changed, 206 insertions(+), 216 deletions(-) diff --git a/actions/actions b/actions/actions index 7b7e5459b..8761c73eb 100755 --- a/actions/actions +++ b/actions/actions @@ -1,210 +1,7 @@ #!/usr/bin/python3 # SPDX-License-Identifier: AGPL-3.0-or-later -import argparse -import importlib -import inspect -import json -import logging -import os -import sys -import traceback -import types -import typing - -import plinth.log -from plinth import cfg, module_loader - -EXIT_SYNTAX = 10 -EXIT_PERM = 20 - -logger = logging.getLogger(__name__) - - -def main(): - """Parse arguments.""" - plinth.log.action_init() - - parser = argparse.ArgumentParser() - parser.add_argument('module', help='Module to trigger action in') - parser.add_argument('action', help='Action to trigger in module') - parser.add_argument('--write-fd', type=int, default=1, - help='File descriptor to write output to') - parser.add_argument('--no-args', default=False, action='store_true', - help='Do not read arguments from stdin') - args = parser.parse_args() - - try: - try: - arguments = {'args': [], 'kwargs': {}} - if not args.no_args: - input_ = sys.stdin.read() - if input_: - arguments = json.loads(input_) - except json.JSONDecodeError as exception: - raise SyntaxError('Arguments on stdin not JSON.') from exception - - return_value = _call(args.module, args.action, arguments) - with os.fdopen(args.write_fd, 'w') as write_file_handle: - write_file_handle.write(json.dumps(return_value)) - except PermissionError as exception: - logger.error(exception.args[0]) - sys.exit(EXIT_PERM) - except SyntaxError as exception: - logger.error(exception.args[0]) - sys.exit(EXIT_SYNTAX) - except TypeError as exception: - logger.error(exception.args[0]) - sys.exit(EXIT_SYNTAX) - except Exception as exception: - logger.exception(exception) - sys.exit(1) - - -def _call(module_name, action_name, arguments): - """Import the module and run action as superuser""" - if '.' in module_name: - raise SyntaxError('Invalid module name') - - cfg.read() - if module_name == 'plinth': - import_path = 'plinth' - else: - import_path = module_loader.get_module_import_path(module_name) - - try: - module = importlib.import_module(import_path + '.privileged') - except ModuleNotFoundError as exception: - raise SyntaxError('Specified module not found') from exception - - try: - action = getattr(module, action_name) - except AttributeError as exception: - raise SyntaxError('Specified action not found') from exception - - if not getattr(action, '_privileged', None): - raise SyntaxError('Specified action is not privileged action') - - func = getattr(action, '__wrapped__') - - _assert_valid_arguments(func, arguments) - - try: - return_values = func(*arguments['args'], **arguments['kwargs']) - return_value = {'result': 'success', 'return': return_values} - except Exception as exception: - logger.exception('Error executing action: %s', exception) - return_value = { - 'result': 'exception', - 'exception': { - 'module': type(exception).__module__, - 'name': type(exception).__name__, - 'args': exception.args, - 'traceback': traceback.format_tb(exception.__traceback__) - } - } - - return return_value - - -def _assert_valid_arguments(func, arguments): - """Check the names, types and completeness of the arguments passed.""" - # Check if arguments match types - if not isinstance(arguments, dict): - raise SyntaxError('Invalid arguments format') - - if 'args' not in arguments or 'kwargs' not in arguments: - raise SyntaxError('Invalid arguments format') - - args = arguments['args'] - kwargs = arguments['kwargs'] - if not isinstance(args, list) or not isinstance(kwargs, dict): - raise SyntaxError('Invalid arguments format') - - argspec = inspect.getfullargspec(func) - if len(args) + len(kwargs) > len(argspec.args): - raise SyntaxError('Too many arguments') - - no_defaults = len(argspec.args) - if argspec.defaults: - no_defaults -= len(argspec.defaults) - - for key in argspec.args[len(args):no_defaults]: - if key not in kwargs: - raise SyntaxError(f'Argument not provided: {key}') - - for key, value in kwargs.items(): - if key not in argspec.args: - raise SyntaxError(f'Unknown argument: {key}') - - if argspec.args.index(key) < len(args): - raise SyntaxError(f'Duplicate argument: {key}') - - _assert_valid_type(f'arg {key}', value, argspec.annotations[key]) - - for index, arg in enumerate(args): - annotation = argspec.annotations[argspec.args[index]] - _assert_valid_type(f'arg #{index}', arg, annotation) - - -def _assert_valid_type(arg_name, value, annotation): - """Assert that the type of argument value matches the annotation.""" - if annotation == typing.Any: - return - - NoneType = type(None) - if annotation == NoneType: - if value is not None: - raise TypeError('Expected None for {arg_name}') - - return - - basic_types = {bool, int, str, float} - if annotation in basic_types: - if not isinstance(value, annotation): - raise TypeError( - f'Expected type {annotation.__name__} for {arg_name}') - - return - - # 'int | str' or 'typing.Union[int, str]' - if (isinstance(annotation, types.UnionType) - or getattr(annotation, '__origin__', None) == typing.Union): - for arg in annotation.__args__: - try: - _assert_valid_type(arg_name, value, arg) - return - except TypeError: - pass - - raise TypeError(f'Expected one of unioned types for {arg_name}') - - # 'list[int]' or 'typing.List[int]' - if getattr(annotation, '__origin__', None) == list: - if not isinstance(value, list): - raise TypeError(f'Expected type list for {arg_name}') - - for index, inner_item in enumerate(value): - _assert_valid_type(f'{arg_name}[{index}]', inner_item, - annotation.__args__[0]) - - return - - # 'list[dict]' or 'typing.List[dict]' - if getattr(annotation, '__origin__', None) == dict: - if not isinstance(value, dict): - raise TypeError(f'Expected type dict for {arg_name}') - - for inner_key, inner_value in value.items(): - _assert_valid_type(f'{arg_name}[{inner_key}]', inner_key, - annotation.__args__[0]) - _assert_valid_type(f'{arg_name}[{inner_value}]', inner_value, - annotation.__args__[1]) - - return - - raise TypeError('Unsupported annotation type') - +from plinth.actions import privileged_main if __name__ == '__main__': - main() + privileged_main() diff --git a/plinth/actions.py b/plinth/actions.py index 187a0bd0b..8f9f1e802 100644 --- a/plinth/actions.py +++ b/plinth/actions.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later """Framework to run specified actions with elevated privileges.""" +import argparse import functools import importlib import inspect @@ -8,9 +9,16 @@ import json import logging import os import subprocess +import sys import threading +import traceback +import types +import typing -from plinth import cfg +from plinth import cfg, log, module_loader + +EXIT_SYNTAX = 10 +EXIT_PERM = 20 logger = logging.getLogger(__name__) @@ -235,3 +243,189 @@ def _log_action(module_name, action_name, run_as_user, run_in_background): prompt = f'({run_as_user})$' if run_as_user else '#' suffix = '&' if run_in_background else '' logger.info('%s %s..%s(…) %s', prompt, module_name, action_name, suffix) + + +def privileged_main(): + """Parse arguments for the program spawned as a privileged action.""" + log.action_init() + + parser = argparse.ArgumentParser() + parser.add_argument('module', help='Module to trigger action in') + parser.add_argument('action', help='Action to trigger in module') + parser.add_argument('--write-fd', type=int, default=1, + help='File descriptor to write output to') + parser.add_argument('--no-args', default=False, action='store_true', + help='Do not read arguments from stdin') + args = parser.parse_args() + + try: + try: + arguments = {'args': [], 'kwargs': {}} + if not args.no_args: + input_ = sys.stdin.read() + if input_: + arguments = json.loads(input_) + except json.JSONDecodeError as exception: + raise SyntaxError('Arguments on stdin not JSON.') from exception + + return_value = _privileged_call(args.module, args.action, arguments) + with os.fdopen(args.write_fd, 'w') as write_file_handle: + write_file_handle.write(json.dumps(return_value)) + except PermissionError as exception: + logger.error(exception.args[0]) + sys.exit(EXIT_PERM) + except SyntaxError as exception: + logger.error(exception.args[0]) + sys.exit(EXIT_SYNTAX) + except TypeError as exception: + logger.error(exception.args[0]) + sys.exit(EXIT_SYNTAX) + except Exception as exception: + logger.exception(exception) + sys.exit(1) + + +def _privileged_call(module_name, action_name, arguments): + """Import the module and run action as superuser""" + if '.' in module_name: + raise SyntaxError('Invalid module name') + + cfg.read() + if module_name == 'plinth': + import_path = 'plinth' + else: + import_path = module_loader.get_module_import_path(module_name) + + try: + module = importlib.import_module(import_path + '.privileged') + except ModuleNotFoundError as exception: + raise SyntaxError('Specified module not found') from exception + + try: + action = getattr(module, action_name) + except AttributeError as exception: + raise SyntaxError('Specified action not found') from exception + + if not getattr(action, '_privileged', None): + raise SyntaxError('Specified action is not privileged action') + + func = getattr(action, '__wrapped__') + + _privileged_assert_valid_arguments(func, arguments) + + try: + return_values = func(*arguments['args'], **arguments['kwargs']) + return_value = {'result': 'success', 'return': return_values} + except Exception as exception: + logger.exception('Error executing action: %s', exception) + return_value = { + 'result': 'exception', + 'exception': { + 'module': type(exception).__module__, + 'name': type(exception).__name__, + 'args': exception.args, + 'traceback': traceback.format_tb(exception.__traceback__) + } + } + + return return_value + + +def _privileged_assert_valid_arguments(func, arguments): + """Check the names, types and completeness of the arguments passed.""" + # Check if arguments match types + if not isinstance(arguments, dict): + raise SyntaxError('Invalid arguments format') + + if 'args' not in arguments or 'kwargs' not in arguments: + raise SyntaxError('Invalid arguments format') + + args = arguments['args'] + kwargs = arguments['kwargs'] + if not isinstance(args, list) or not isinstance(kwargs, dict): + raise SyntaxError('Invalid arguments format') + + argspec = inspect.getfullargspec(func) + if len(args) + len(kwargs) > len(argspec.args): + raise SyntaxError('Too many arguments') + + no_defaults = len(argspec.args) + if argspec.defaults: + no_defaults -= len(argspec.defaults) + + for key in argspec.args[len(args):no_defaults]: + if key not in kwargs: + raise SyntaxError(f'Argument not provided: {key}') + + for key, value in kwargs.items(): + if key not in argspec.args: + raise SyntaxError(f'Unknown argument: {key}') + + if argspec.args.index(key) < len(args): + raise SyntaxError(f'Duplicate argument: {key}') + + _privileged_assert_valid_type(f'arg {key}', value, + argspec.annotations[key]) + + for index, arg in enumerate(args): + annotation = argspec.annotations[argspec.args[index]] + _privileged_assert_valid_type(f'arg #{index}', arg, annotation) + + +def _privileged_assert_valid_type(arg_name, value, annotation): + """Assert that the type of argument value matches the annotation.""" + if annotation == typing.Any: + return + + NoneType = type(None) + if annotation == NoneType: + if value is not None: + raise TypeError('Expected None for {arg_name}') + + return + + basic_types = {bool, int, str, float} + if annotation in basic_types: + if not isinstance(value, annotation): + raise TypeError( + f'Expected type {annotation.__name__} for {arg_name}') + + return + + # 'int | str' or 'typing.Union[int, str]' + if (isinstance(annotation, types.UnionType) + or getattr(annotation, '__origin__', None) == typing.Union): + for arg in annotation.__args__: + try: + _privileged_assert_valid_type(arg_name, value, arg) + return + except TypeError: + pass + + raise TypeError(f'Expected one of unioned types for {arg_name}') + + # 'list[int]' or 'typing.List[int]' + if getattr(annotation, '__origin__', None) == list: + if not isinstance(value, list): + raise TypeError(f'Expected type list for {arg_name}') + + for index, inner_item in enumerate(value): + _privileged_assert_valid_type(f'{arg_name}[{index}]', inner_item, + annotation.__args__[0]) + + return + + # 'list[dict]' or 'typing.List[dict]' + if getattr(annotation, '__origin__', None) == dict: + if not isinstance(value, dict): + raise TypeError(f'Expected type dict for {arg_name}') + + for inner_key, inner_value in value.items(): + _privileged_assert_valid_type(f'{arg_name}[{inner_key}]', + inner_key, annotation.__args__[0]) + _privileged_assert_valid_type(f'{arg_name}[{inner_value}]', + inner_value, annotation.__args__[1]) + + return + + raise TypeError('Unsupported annotation type') diff --git a/plinth/tests/test_actions_actions.py b/plinth/tests/test_actions_actions.py index 088fa6fa4..5ae5fa68a 100644 --- a/plinth/tests/test_actions_actions.py +++ b/plinth/tests/test_actions_actions.py @@ -9,7 +9,7 @@ from unittest.mock import patch import pytest -from plinth.actions import privileged +from plinth import actions actions_name = 'actions' @@ -17,10 +17,9 @@ actions_name = 'actions' @patch('importlib.import_module') @patch('plinth.module_loader.get_module_import_path') @patch('os.getuid') -def test_call_syntax_checks(getuid, get_module_import_path, import_module, - actions_module): +def test_call_syntax_checks(getuid, get_module_import_path, import_module): """Test that calling a method results in proper syntax checks.""" - call = actions_module._call + call = actions._privileged_call # Module name validation getuid.return_value = 0 @@ -53,7 +52,7 @@ def test_call_syntax_checks(getuid, get_module_import_path, import_module, call('test-module', 'func', {}) # Argument validation - @privileged + @actions.privileged def func(): return 'foo' @@ -66,7 +65,7 @@ def test_call_syntax_checks(getuid, get_module_import_path, import_module, assert return_value == {'result': 'success', 'return': 'foo'} # Exception call - @privileged + @actions.privileged def exception_func(): raise RuntimeError('foo exception') @@ -81,9 +80,9 @@ def test_call_syntax_checks(getuid, get_module_import_path, import_module, assert isinstance(line, str) -def test_assert_valid_arguments(actions_module): +def test_assert_valid_arguments(): """Test that checking valid arguments works.""" - assert_valid = actions_module._assert_valid_arguments + assert_valid = actions._privileged_assert_valid_arguments values = [ None, [], 10, {}, { @@ -139,9 +138,9 @@ def test_assert_valid_arguments(actions_module): assert_valid(func, {'args': [1, '2'], 'kwargs': {'c': '3'}}) -def test_assert_valid_type(actions_module): +def test_assert_valid_type(): """Test that type validation works as expected.""" - assert_valid = actions_module._assert_valid_type + assert_valid = actions._privileged_assert_valid_type assert_valid(None, None, typing.Any) From 4b5f48daed7aa08f277bdf6c01a7da8d93402bba Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sun, 10 Mar 2024 11:40:41 -0700 Subject: [PATCH 36/63] tests: Remove unused fixture for testing actions Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- conftest.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/conftest.py b/conftest.py index 244b98ade..a5611c477 100644 --- a/conftest.py +++ b/conftest.py @@ -133,21 +133,6 @@ def splinter_browser_load_condition(): return _load_condition -@pytest.fixture(name='actions_module', scope='module') -def fixture_actions_module(request): - """Import and return an action module.""" - actions_name = getattr(request.module, 'actions_name') - actions_file = str( - pathlib.Path(__file__).parent / 'actions' / actions_name) - - loader = importlib.machinery.SourceFileLoader(actions_name, actions_file) - spec = importlib.util.spec_from_loader(actions_name, loader) - module = importlib.util.module_from_spec(spec) - sys.modules[actions_name] = module - spec.loader.exec_module(module) - return module - - @pytest.fixture(name='mock_privileged') def fixture_mock_privileged(request): """Mock the privileged decorator to nullify its effects.""" From a14578c50d3df4bb9979747ed308a37a02ddbe93 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sun, 10 Mar 2024 11:41:32 -0700 Subject: [PATCH 37/63] tests: Move test configuration to plinth directory Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- conftest.py | 232 +------------------------------------------ plinth/conftest.py | 243 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 231 deletions(-) create mode 100644 plinth/conftest.py diff --git a/conftest.py b/conftest.py index a5611c477..495bc791f 100644 --- a/conftest.py +++ b/conftest.py @@ -1,240 +1,10 @@ # SPDX-License-Identifier: AGPL-3.0-or-later """ -pytest configuration for all tests. +pytest configuration that needs to be pytest rootdir. """ -import importlib -import os -import pathlib -import sys - -import pytest - -try: - importlib.import_module('splinter') - importlib.import_module('selenium') - _functional_libs_available = True -except ImportError: - _functional_libs_available = False - - -def pytest_ignore_collect(path, config): - """Ignore functional tests when splinter is not available.""" - if path.basename == 'test_functional.py': - return not _functional_libs_available - def pytest_addoption(parser): """Add a command line option to run functional tests.""" parser.addoption('--include-functional', action='store_true', default=False, help='Run functional tests also') - - -def pytest_collection_modifyitems(config, items): - """Filter out specificly marked tests unless explicitly requested. - - The EXTENDED_TESTING environment variable is borrowed from the Lancaster - consensus met by the Pearl community. See - https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md - """ - - def skip(item, reason): - item.add_marker(pytest.mark.skip(reason=reason)) - - extended = 'EXTENDED_TESTING' in os.environ - if not (extended or config.getoption('--include-functional')): - for item in items: - if 'functional' in item.keywords or ( - item.parent.fspath.basename - and item.parent.fspath.basename == 'test_functional.py'): - skip(item, '--include-functional not provided') - - if not extended: - for item in items: - if 'heavy' in item.keywords: - skip(item, ('Takes too much time. ' - 'Set EXTENDED_TESTING=1 to force run')) - - -@pytest.fixture(name='load_cfg') -def fixture_load_cfg(): - """Load test configuration.""" - from plinth import cfg - - keys = ('file_root', 'config_dir', 'data_dir', 'custom_static_dir', - 'store_file', 'actions_dir', 'doc_dir', 'server_dir', 'host', - 'port', 'use_x_forwarded_for', 'use_x_forwarded_host', - 'secure_proxy_ssl_header', 'box_name', 'develop') - saved_state = {} - for key in keys: - saved_state[key] = getattr(cfg, key) - - root_dir = pathlib.Path(__file__).resolve().parent - cfg_file = root_dir / 'plinth' / 'develop.config' - cfg.read_file(str(cfg_file)) - yield cfg - - for key in keys: - setattr(cfg, key, saved_state[key]) - - -@pytest.fixture(name='develop_mode') -def fixture_develop_mode(load_cfg): - """Turn on development mode for a test.""" - load_cfg.develop = True - yield - load_cfg.develop = False - - -@pytest.fixture(name='needs_root', scope='session') -def fixture_needs_root(): - """Skip test if not running in root mode.""" - if os.geteuid() != 0: - pytest.skip('Needs to be root') - - -@pytest.fixture(name='needs_not_root', scope='session') -def fixture_needs_not_root(): - """Skip test if running in root mode.""" - if os.geteuid() == 0: - pytest.skip('Needs not to be root') - - -@pytest.fixture(name='needs_sudo') -def fixture_needs_sudo(): - """Skip test if sudo command is not available.""" - if not os.path.isfile('/usr/bin/sudo'): - pytest.skip('Needs sudo command installed.') - - -@pytest.fixture(scope='session') -def splinter_selenium_implicit_wait(): - """Disable implicit waiting.""" - return 0 - - -@pytest.fixture(scope='session') -def splinter_wait_time(): - """Disable explicit waiting.""" - return 0.01 - - -@pytest.fixture(scope='session') -def splinter_browser_load_condition(): - """When a page it loaded, wait until is available.""" - - def _load_condition(browser): - if browser.url == 'about:blank': - return True - - ready_state = browser.execute_script('return document.readyState;') - return ready_state == 'complete' - - return _load_condition - - -@pytest.fixture(name='mock_privileged') -def fixture_mock_privileged(request): - """Mock the privileged decorator to nullify its effects.""" - try: - privileged_modules_to_mock = request.module.privileged_modules_to_mock - except AttributeError: - raise AttributeError( - 'mock_privileged fixture requires "privileged_module_to_mock" ' - 'attribute at module level') - - for module_name in privileged_modules_to_mock: - module = importlib.import_module(module_name) - for name, member in module.__dict__.items(): - wrapped = getattr(member, '__wrapped__', None) - if not callable(member) or not wrapped: - continue - - if not getattr(member, '_privileged', False): - continue - - setattr(wrapped, '_original_wrapper', member) - module.__dict__[name] = wrapped - - yield - - for module_name in privileged_modules_to_mock: - module = importlib.import_module(module_name) - for name, member in module.__dict__.items(): - wrapper = getattr(member, '_original_wrapper', None) - if not callable(member) or not wrapper: - continue - - module.__dict__[name] = wrapper - - -@pytest.fixture(name='splinter_screenshot_dir', scope='session') -def fixture_splinter_screenshot_dir(request): - """Set default screenshot directory to ./screenshots. - - This can be overridden using --splinter-screenshot-dir=foo as the option. - """ - option = request.config.getoption('--splinter-screenshot-dir') - screenshots_dir = option if option != '.' else './screenshots' - return os.path.abspath(screenshots_dir) - - -@pytest.fixture(autouse=True) -def fixture_fix_session_browser_screenshots(request): - """Fix a bug in pytest-splinter for screenshots. - - When using session_browser, pytest-splinter does not take a screenshot when - a test has failed. It is uses internal pytest API on the FixtureRequest - object. This API was removed in later versions of pytest causing the - failure. Re-implement the fixture that has the problem fixing this issue. - - Drop this fixture after a fix is merged and released in pytest-splinter. - See: https://github.com/pytest-dev/pytest-splinter/pull/157 - """ - yield - - if not request.config.pluginmanager.has_plugin('pytest-splinter'): - return - - session_tmpdir = request.getfixturevalue('session_tmpdir') - splinter_session_scoped_browser = request.getfixturevalue( - 'splinter_session_scoped_browser') - splinter_make_screenshot_on_failure = request.getfixturevalue( - 'splinter_make_screenshot_on_failure') - splinter_screenshot_dir = request.getfixturevalue( - 'splinter_screenshot_dir') - splinter_screenshot_getter_html = request.getfixturevalue( - 'splinter_screenshot_getter_html') - splinter_screenshot_getter_png = request.getfixturevalue( - 'splinter_screenshot_getter_png') - splinter_screenshot_encoding = request.getfixturevalue( - 'splinter_screenshot_encoding') - - # Screenshot for function scoped browsers is handled in - # browser_instance_getter - if not splinter_session_scoped_browser: - return - - for name in request.fixturenames: - fixture_def = request._fixture_defs.get(name) - if not fixture_def or not fixture_def.cached_result: - continue - - value = fixture_def.cached_result[0] - should_take_screenshot = (hasattr(value, "__splinter_browser__") - and splinter_make_screenshot_on_failure - and getattr(request.node, 'splinter_failure', - True)) - - from pytest_splinter import plugin - if should_take_screenshot: - plugin._take_screenshot( - request=request, - fixture_name=name, - session_tmpdir=session_tmpdir, - browser_instance=value, - splinter_screenshot_dir=splinter_screenshot_dir, - splinter_screenshot_getter_html=splinter_screenshot_getter_html, - splinter_screenshot_getter_png=splinter_screenshot_getter_png, - splinter_screenshot_encoding=splinter_screenshot_encoding, - ) diff --git a/plinth/conftest.py b/plinth/conftest.py new file mode 100644 index 000000000..8df2a4f8d --- /dev/null +++ b/plinth/conftest.py @@ -0,0 +1,243 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +""" +pytest configuration for all tests. +""" + +import importlib +import os +import pathlib + +import pytest + +try: + importlib.import_module('splinter') + importlib.import_module('selenium') + _functional_libs_available = True +except ImportError: + _functional_libs_available = False + + +def pytest_ignore_collect(path, config): + """Ignore functional tests when splinter is not available.""" + if path.basename == 'test_functional.py': + return not _functional_libs_available + + +def pytest_collection_modifyitems(config, items): + """Filter out specificly marked tests unless explicitly requested. + + The EXTENDED_TESTING environment variable is borrowed from the Lancaster + consensus met by the Pearl community. See + https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lancaster-consensus.md + """ + + def skip(item, reason): + item.add_marker(pytest.mark.skip(reason=reason)) + + extended = 'EXTENDED_TESTING' in os.environ + if not (extended or config.getoption('--include-functional')): + for item in items: + if 'functional' in item.keywords or ( + item.parent.fspath.basename + and item.parent.fspath.basename == 'test_functional.py'): + skip(item, '--include-functional not provided') + + if not extended: + for item in items: + if 'heavy' in item.keywords: + skip(item, ('Takes too much time. ' + 'Set EXTENDED_TESTING=1 to force run')) + + +@pytest.fixture(name='load_cfg') +def fixture_load_cfg(): + """Load test configuration.""" + from plinth import cfg + + keys = ('file_root', 'config_dir', 'data_dir', 'custom_static_dir', + 'store_file', 'actions_dir', 'doc_dir', 'server_dir', 'host', + 'port', 'use_x_forwarded_for', 'use_x_forwarded_host', + 'secure_proxy_ssl_header', 'box_name', 'develop') + saved_state = {} + for key in keys: + saved_state[key] = getattr(cfg, key) + + root_dir = pathlib.Path(__file__).resolve().parent + cfg_file = root_dir / 'plinth' / 'develop.config' + cfg.read_file(str(cfg_file)) + yield cfg + + for key in keys: + setattr(cfg, key, saved_state[key]) + + +@pytest.fixture(name='develop_mode') +def fixture_develop_mode(load_cfg): + """Turn on development mode for a test.""" + load_cfg.develop = True + yield + load_cfg.develop = False + + +@pytest.fixture(name='needs_root', scope='session') +def fixture_needs_root(): + """Skip test if not running in root mode.""" + if os.geteuid() != 0: + pytest.skip('Needs to be root') + + +@pytest.fixture(name='needs_not_root', scope='session') +def fixture_needs_not_root(): + """Skip test if running in root mode.""" + if os.geteuid() == 0: + pytest.skip('Needs not to be root') + + +@pytest.fixture(name='needs_sudo') +def fixture_needs_sudo(): + """Skip test if sudo command is not available.""" + if not os.path.isfile('/usr/bin/sudo'): + pytest.skip('Needs sudo command installed.') + + +@pytest.fixture(scope='session') +def splinter_selenium_implicit_wait(): + """Disable implicit waiting.""" + return 0 + + +@pytest.fixture(scope='session') +def splinter_wait_time(): + """Disable explicit waiting.""" + return 0.01 + + +@pytest.fixture(scope='session') +def splinter_browser_load_condition(): + """When a page it loaded, wait until is available.""" + + def _load_condition(browser): + if browser.url == 'about:blank': + return True + + ready_state = browser.execute_script('return document.readyState;') + return ready_state == 'complete' + + return _load_condition + + +@pytest.fixture(name='mock_privileged') +def fixture_mock_privileged(request): + """Mock the privileged decorator to nullify its effects.""" + try: + privileged_modules_to_mock = request.module.privileged_modules_to_mock + except AttributeError: + raise AttributeError( + 'mock_privileged fixture requires "privileged_module_to_mock" ' + 'attribute at module level') + + for module_name in privileged_modules_to_mock: + module = importlib.import_module(module_name) + for name, member in module.__dict__.items(): + wrapped = getattr(member, '__wrapped__', None) + if not callable(member) or not wrapped: + continue + + if not getattr(member, '_privileged', False): + continue + + setattr(wrapped, '_original_wrapper', member) + module.__dict__[name] = wrapped + + yield + + for module_name in privileged_modules_to_mock: + module = importlib.import_module(module_name) + for name, member in module.__dict__.items(): + wrapper = getattr(member, '_original_wrapper', None) + if not callable(member) or not wrapper: + continue + + module.__dict__[name] = wrapper + + +@pytest.fixture(name='splinter_screenshot_dir', scope='session') +def fixture_splinter_screenshot_dir(request): + """Set default screenshot directory to ./screenshots. + + This can be overridden using --splinter-screenshot-dir=foo as the option. + """ + option = request.config.getoption('--splinter-screenshot-dir') + screenshots_dir = option if option != '.' else './screenshots' + return os.path.abspath(screenshots_dir) + + +@pytest.fixture(autouse=True) +def fixture_fix_session_browser_screenshots(request): + """Fix a bug in pytest-splinter for screenshots. + + When using session_browser, pytest-splinter does not take a screenshot when + a test has failed. It is uses internal pytest API on the FixtureRequest + object. This API was removed in later versions of pytest causing the + failure. Re-implement the fixture that has the problem fixing this issue. + + Drop this fixture after a fix is merged and released in pytest-splinter. + See: https://github.com/pytest-dev/pytest-splinter/pull/157 + """ + yield + + if not request.config.pluginmanager.has_plugin('pytest-splinter'): + return + + session_tmpdir = request.getfixturevalue('session_tmpdir') + splinter_session_scoped_browser = request.getfixturevalue( + 'splinter_session_scoped_browser') + splinter_make_screenshot_on_failure = request.getfixturevalue( + 'splinter_make_screenshot_on_failure') + splinter_screenshot_dir = request.getfixturevalue( + 'splinter_screenshot_dir') + splinter_screenshot_getter_html = request.getfixturevalue( + 'splinter_screenshot_getter_html') + splinter_screenshot_getter_png = request.getfixturevalue( + 'splinter_screenshot_getter_png') + splinter_screenshot_encoding = request.getfixturevalue( + 'splinter_screenshot_encoding') + + # Screenshot for function scoped browsers is handled in + # browser_instance_getter + if not splinter_session_scoped_browser: + return + + for name in request.fixturenames: + fixture_def = request._fixture_defs.get(name) + if not fixture_def or not fixture_def.cached_result: + continue + + value = fixture_def.cached_result[0] + should_take_screenshot = (hasattr(value, "__splinter_browser__") + and splinter_make_screenshot_on_failure + and getattr(request.node, 'splinter_failure', + True)) + + from pytest_splinter import plugin + if should_take_screenshot: + kwargs = { + 'request': + request, + 'fixture_name': + name, + 'session_tmpdir': + session_tmpdir, + 'browser_instance': + value, + 'splinter_screenshot_dir': + splinter_screenshot_dir, + 'splinter_screenshot_getter_html': + splinter_screenshot_getter_html, + 'splinter_screenshot_getter_png': + splinter_screenshot_getter_png, + 'splinter_screenshot_encoding': + splinter_screenshot_encoding + } + + plugin._take_screenshot(**kwargs) From 157abb023ab8fa10337d5e736d17eedfdad6c756 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sun, 10 Mar 2024 11:54:07 -0700 Subject: [PATCH 38/63] tests: Merge actions related test files Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/tests/test_actions.py | 173 +++++++++++++++++++++++++- plinth/tests/test_actions_actions.py | 176 --------------------------- 2 files changed, 172 insertions(+), 177 deletions(-) delete mode 100644 plinth/tests/test_actions_actions.py diff --git a/plinth/tests/test_actions.py b/plinth/tests/test_actions.py index 4a1f1dc1d..b4e8f3f3f 100644 --- a/plinth/tests/test_actions.py +++ b/plinth/tests/test_actions.py @@ -10,13 +10,16 @@ description of the expectations. import json import os import subprocess +import typing from unittest.mock import Mock, call, patch import pytest -from plinth import cfg +from plinth import actions, cfg from plinth.actions import privileged +actions_name = 'actions' + @pytest.fixture(name='popen') def fixture_popen(): @@ -140,3 +143,171 @@ def test_privileged_method_exceptions(get_module_name, popen): wrapped_func = privileged(func_with_exception) with pytest.raises(TypeError, match='type error'): wrapped_func() + + +@patch('importlib.import_module') +@patch('plinth.module_loader.get_module_import_path') +@patch('os.getuid') +def test_call_syntax_checks(getuid, get_module_import_path, import_module): + """Test that calling a method results in proper syntax checks.""" + privileged_call = actions._privileged_call + + # Module name validation + getuid.return_value = 0 + with pytest.raises(SyntaxError, match='Invalid module name'): + privileged_call('foo.bar', 'x-action', {}) + + # Module import test + get_module_import_path.return_value = 'plinth.modules.test_module' + import_module.side_effect = ModuleNotFoundError + with pytest.raises(SyntaxError, match='Specified module not found'): + privileged_call('test_module', 'x-action', {}) + + import_module.assert_has_calls( + [call('plinth.modules.test_module.privileged')]) + + # Finding action in a module + module = type('', (), {}) + import_module.side_effect = None + import_module.return_value = module + with pytest.raises(SyntaxError, match='Specified action not found'): + privileged_call('test_module', 'x-action', {}) + + # Checking if action is privileged + def unprivileged_func(): + pass + + setattr(module, 'func', unprivileged_func) + with pytest.raises(SyntaxError, + match='Specified action is not privileged action'): + privileged_call('test-module', 'func', {}) + + # Argument validation + @actions.privileged + def func(): + return 'foo' + + setattr(module, 'func', func) + with pytest.raises(SyntaxError, match='Invalid arguments format'): + privileged_call('test-module', 'func', {}) + + # Successful call + return_value = privileged_call('test-module', 'func', { + 'args': [], + 'kwargs': {} + }) + assert return_value == {'result': 'success', 'return': 'foo'} + + # Exception call + @actions.privileged + def exception_func(): + raise RuntimeError('foo exception') + + setattr(module, 'func', exception_func) + return_value = privileged_call('test-module', 'func', { + 'args': [], + 'kwargs': {} + }) + assert return_value['result'] == 'exception' + assert return_value['exception']['module'] == 'builtins' + assert return_value['exception']['name'] == 'RuntimeError' + assert return_value['exception']['args'] == ('foo exception', ) + assert isinstance(return_value['exception']['traceback'], list) + for line in return_value['exception']['traceback']: + assert isinstance(line, str) + + +def test_assert_valid_arguments(): + """Test that checking valid arguments works.""" + assert_valid = actions._privileged_assert_valid_arguments + + values = [ + None, [], 10, {}, { + 'args': [] + }, { + 'kwargs': {} + }, { + 'args': {}, + 'kwargs': {} + }, { + 'args': [], + 'kwargs': [] + } + ] + for value in values: + with pytest.raises(SyntaxError, match='Invalid arguments format'): + assert_valid(lambda: None, value) + + def func(a: int, b: str, c: int = 3, d: str = 'foo'): + pass + + with pytest.raises(SyntaxError, match='Too many arguments'): + assert_valid(func, {'args': [1, 2, 3], 'kwargs': {'c': 3, 'd': 4}}) + + with pytest.raises(SyntaxError, match='Too many arguments'): + assert_valid(func, {'args': [1, 2, 3, 4, 5], 'kwargs': {}}) + + with pytest.raises(SyntaxError, match='Too many arguments'): + assert_valid(func, { + 'args': [], + 'kwargs': { + 'a': 1, + 'b': '2', + 'c': 3, + 'd': '4', + 'e': 5 + } + }) + + with pytest.raises(SyntaxError, match='Argument not provided: b'): + assert_valid(func, {'args': [1], 'kwargs': {}}) + + with pytest.raises(SyntaxError, match='Unknown argument: e'): + assert_valid(func, {'args': [1, '2'], 'kwargs': {'e': 5}}) + + with pytest.raises(SyntaxError, match='Duplicate argument: c'): + assert_valid(func, {'args': [1, '2', 3], 'kwargs': {'c': 4}}) + + with pytest.raises(TypeError, match='Expected type str for arg #1'): + assert_valid(func, {'args': [1, 2], 'kwargs': {}}) + + with pytest.raises(TypeError, match='Expected type int for arg c'): + assert_valid(func, {'args': [1, '2'], 'kwargs': {'c': '3'}}) + + +def test_assert_valid_type(): + """Test that type validation works as expected.""" + assert_valid = actions._privileged_assert_valid_type + + assert_valid(None, None, typing.Any) + + # Invalid values for int, str, float and Optional + values = [[1, bool], ['foo', int], [1, str], [1, float], + [1, typing.Optional[str]], [1, str | None], + [1.1, typing.Union[int, str]], [1.1, int | str], [1, list], + [1, dict], [[1], list[str]], [{ + 'a': 'b' + }, dict[int, str]], [{ + 1: 2 + }, dict[int, str]]] + for value in values: + with pytest.raises(TypeError): + assert_valid('arg', *value) + + # Valid values + assert_valid('arg', True, bool) + assert_valid('arg', 1, int) + assert_valid('arg', '1', str) + assert_valid('arg', 1.1, float) + assert_valid('arg', None, typing.Optional[int]) + assert_valid('arg', 1, typing.Optional[int]) + assert_valid('arg', None, int | None) + assert_valid('arg', 1, int | None) + assert_valid('arg', 1, typing.Union[int, str]) + assert_valid('arg', '1', typing.Union[int, str]) + assert_valid('arg', 1, int | str) + assert_valid('arg', '1', int | str) + assert_valid('arg', [], list[int]) + assert_valid('arg', ['foo'], list[str]) + assert_valid('arg', {}, dict[int, str]) + assert_valid('arg', {1: 'foo'}, dict[int, str]) diff --git a/plinth/tests/test_actions_actions.py b/plinth/tests/test_actions_actions.py deleted file mode 100644 index 5ae5fa68a..000000000 --- a/plinth/tests/test_actions_actions.py +++ /dev/null @@ -1,176 +0,0 @@ -# SPDX-License-Identifier: AGPL-3.0-or-later -""" -Test module for code that runs methods are privileged actions. -""" - -import typing -from unittest.mock import call as mock_call -from unittest.mock import patch - -import pytest - -from plinth import actions - -actions_name = 'actions' - - -@patch('importlib.import_module') -@patch('plinth.module_loader.get_module_import_path') -@patch('os.getuid') -def test_call_syntax_checks(getuid, get_module_import_path, import_module): - """Test that calling a method results in proper syntax checks.""" - call = actions._privileged_call - - # Module name validation - getuid.return_value = 0 - with pytest.raises(SyntaxError, match='Invalid module name'): - call('foo.bar', 'x-action', {}) - - # Module import test - get_module_import_path.return_value = 'plinth.modules.test_module' - import_module.side_effect = ModuleNotFoundError - with pytest.raises(SyntaxError, match='Specified module not found'): - call('test_module', 'x-action', {}) - - import_module.assert_has_calls( - [mock_call('plinth.modules.test_module.privileged')]) - - # Finding action in a module - module = type('', (), {}) - import_module.side_effect = None - import_module.return_value = module - with pytest.raises(SyntaxError, match='Specified action not found'): - call('test_module', 'x-action', {}) - - # Checking if action is privileged - def unprivileged_func(): - pass - - setattr(module, 'func', unprivileged_func) - with pytest.raises(SyntaxError, - match='Specified action is not privileged action'): - call('test-module', 'func', {}) - - # Argument validation - @actions.privileged - def func(): - return 'foo' - - setattr(module, 'func', func) - with pytest.raises(SyntaxError, match='Invalid arguments format'): - call('test-module', 'func', {}) - - # Successful call - return_value = call('test-module', 'func', {'args': [], 'kwargs': {}}) - assert return_value == {'result': 'success', 'return': 'foo'} - - # Exception call - @actions.privileged - def exception_func(): - raise RuntimeError('foo exception') - - setattr(module, 'func', exception_func) - return_value = call('test-module', 'func', {'args': [], 'kwargs': {}}) - assert return_value['result'] == 'exception' - assert return_value['exception']['module'] == 'builtins' - assert return_value['exception']['name'] == 'RuntimeError' - assert return_value['exception']['args'] == ('foo exception', ) - assert isinstance(return_value['exception']['traceback'], list) - for line in return_value['exception']['traceback']: - assert isinstance(line, str) - - -def test_assert_valid_arguments(): - """Test that checking valid arguments works.""" - assert_valid = actions._privileged_assert_valid_arguments - - values = [ - None, [], 10, {}, { - 'args': [] - }, { - 'kwargs': {} - }, { - 'args': {}, - 'kwargs': {} - }, { - 'args': [], - 'kwargs': [] - } - ] - for value in values: - with pytest.raises(SyntaxError, match='Invalid arguments format'): - assert_valid(lambda: None, value) - - def func(a: int, b: str, c: int = 3, d: str = 'foo'): - pass - - with pytest.raises(SyntaxError, match='Too many arguments'): - assert_valid(func, {'args': [1, 2, 3], 'kwargs': {'c': 3, 'd': 4}}) - - with pytest.raises(SyntaxError, match='Too many arguments'): - assert_valid(func, {'args': [1, 2, 3, 4, 5], 'kwargs': {}}) - - with pytest.raises(SyntaxError, match='Too many arguments'): - assert_valid(func, { - 'args': [], - 'kwargs': { - 'a': 1, - 'b': '2', - 'c': 3, - 'd': '4', - 'e': 5 - } - }) - - with pytest.raises(SyntaxError, match='Argument not provided: b'): - assert_valid(func, {'args': [1], 'kwargs': {}}) - - with pytest.raises(SyntaxError, match='Unknown argument: e'): - assert_valid(func, {'args': [1, '2'], 'kwargs': {'e': 5}}) - - with pytest.raises(SyntaxError, match='Duplicate argument: c'): - assert_valid(func, {'args': [1, '2', 3], 'kwargs': {'c': 4}}) - - with pytest.raises(TypeError, match='Expected type str for arg #1'): - assert_valid(func, {'args': [1, 2], 'kwargs': {}}) - - with pytest.raises(TypeError, match='Expected type int for arg c'): - assert_valid(func, {'args': [1, '2'], 'kwargs': {'c': '3'}}) - - -def test_assert_valid_type(): - """Test that type validation works as expected.""" - assert_valid = actions._privileged_assert_valid_type - - assert_valid(None, None, typing.Any) - - # Invalid values for int, str, float and Optional - values = [[1, bool], ['foo', int], [1, str], [1, float], - [1, typing.Optional[str]], [1, str | None], - [1.1, typing.Union[int, str]], [1.1, int | str], [1, list], - [1, dict], [[1], list[str]], [{ - 'a': 'b' - }, dict[int, str]], [{ - 1: 2 - }, dict[int, str]]] - for value in values: - with pytest.raises(TypeError): - assert_valid('arg', *value) - - # Valid values - assert_valid('arg', True, bool) - assert_valid('arg', 1, int) - assert_valid('arg', '1', str) - assert_valid('arg', 1.1, float) - assert_valid('arg', None, typing.Optional[int]) - assert_valid('arg', 1, typing.Optional[int]) - assert_valid('arg', None, int | None) - assert_valid('arg', 1, int | None) - assert_valid('arg', 1, typing.Union[int, str]) - assert_valid('arg', '1', typing.Union[int, str]) - assert_valid('arg', 1, int | str) - assert_valid('arg', '1', int | str) - assert_valid('arg', [], list[int]) - assert_valid('arg', ['foo'], list[str]) - assert_valid('arg', {}, dict[int, str]) - assert_valid('arg', {1: 'foo'}, dict[int, str]) From a3b6506a4e04cfbc62d7054429bb71488500f514 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sun, 10 Mar 2024 12:14:24 -0700 Subject: [PATCH 39/63] tests: Automatically create pytest marks for apps Fixes: #2388. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/conftest.py | 9 ++++++++ pyproject.toml | 54 ---------------------------------------------- 2 files changed, 9 insertions(+), 54 deletions(-) diff --git a/plinth/conftest.py b/plinth/conftest.py index 8df2a4f8d..9236f7fa6 100644 --- a/plinth/conftest.py +++ b/plinth/conftest.py @@ -23,6 +23,15 @@ def pytest_ignore_collect(path, config): return not _functional_libs_available +def pytest_configure(config): + """Register additional markers, one for each app.""" + for app in (pathlib.Path(__file__).parent / 'modules').iterdir(): + if not app.is_dir(): + continue + + config.addinivalue_line('markers', app.name) + + def pytest_collection_modifyitems(config, items): """Filter out specificly marked tests unless explicitly requested. diff --git a/pyproject.toml b/pyproject.toml index 2a035450f..0cfa98b4a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,62 +136,8 @@ markers = [ "skip", "heavy", "apps", - "avahi", - "backups", - "bepasty", - "bind", - "calibre", - "cockpit", - "config", - "coturn", - "datetime", - "deluge", "domain", - "dynamicdns", - "ejabberd", - "email", - "gitweb", - "help", - "i2p", - "ikiwiki", - "infinoted", - "janus", - "jsxc", - "matrixsynapse", - "mediawiki", - "minetest", - "minidlna", - "mumble", - "openvpn", - "pagekite", - "performance", - "privacy", - "privoxy", - "quassel", - "radicale", - "roundcube", - "rssbridge", - "samba", - "searx", - "security", - "shaarli", - "shadowsocks", - "shadowsocksserver", - "sharing", - "snapshot", - "ssh", - "sso", - "storage", - "syncthing", "system", - "tor", - "transmission", - "ttrss", - "upgrades", - "users", - "wireguard", - "wordpress", - "zoph", ] # Useful when pylint is invoked separately instead of flake8 From 9d2a11b874c9f68a5361a37305cf5b5f4bfb8c41 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 13 Mar 2024 00:29:05 -0700 Subject: [PATCH 40/63] users: Add email address field when creating/updating user accounts Closes: #1826. Signed-off-by: Sunil Mohan Adapa Reviewed-by: Veiko Aasa --- plinth/modules/users/forms.py | 28 +++++++++++++------ plinth/modules/users/tests/test_functional.py | 28 ++++++++++++++++++- plinth/tests/functional/__init__.py | 4 ++- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py index 4abc8bcf8..5f889bb48 100644 --- a/plinth/modules/users/forms.py +++ b/plinth/modules/users/forms.py @@ -59,6 +59,18 @@ def _create_django_groups(): return group_choices +class EmailFieldMixin: + """Mixin to set common properties for the email field.""" + + def __init__(self, *args, **kwargs): + """Set basic properties for the email field.""" + super().__init__(*args, **kwargs) + + self.fields['email'].help_text = _( + 'Optional. Used to send emails to reset password and important ' + 'notifications.') + + class GroupsFieldMixin: """Mixin to set common properties for the group field.""" @@ -146,8 +158,8 @@ class PasswordConfirmForm(forms.Form): return confirm_password -class CreateUserForm(ValidNewUsernameCheckMixin, GroupsFieldMixin, - plinth.forms.LanguageSelectionFormMixin, +class CreateUserForm(ValidNewUsernameCheckMixin, EmailFieldMixin, + GroupsFieldMixin, plinth.forms.LanguageSelectionFormMixin, PasswordConfirmForm, UserCreationForm): """Custom user create form. @@ -161,8 +173,8 @@ class CreateUserForm(ValidNewUsernameCheckMixin, GroupsFieldMixin, class Meta(UserCreationForm.Meta): """Metadata to control automatic form building.""" - fields = ('username', 'password1', 'password2', 'groups', 'language', - 'confirm_password') + fields = ('username', 'email', 'password1', 'password2', 'groups', + 'language', 'confirm_password') widgets = { 'groups': plinth.forms.CheckboxSelectMultiple(), } @@ -219,8 +231,8 @@ class CreateUserForm(ValidNewUsernameCheckMixin, GroupsFieldMixin, class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, - GroupsFieldMixin, plinth.forms.LanguageSelectionFormMixin, - forms.ModelForm): + EmailFieldMixin, GroupsFieldMixin, + plinth.forms.LanguageSelectionFormMixin, forms.ModelForm): """When user info is changed, also updates LDAP user.""" username = USERNAME_FIELD @@ -238,8 +250,8 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, class Meta: """Metadata to control automatic form building.""" - fields = ('username', 'groups', 'ssh_keys', 'language', 'is_active', - 'confirm_password') + fields = ('username', 'email', 'groups', 'ssh_keys', 'language', + 'is_active', 'confirm_password') model = User widgets = { 'groups': plinth.forms.CheckboxSelectMultipleWithReadOnly(), diff --git a/plinth/modules/users/tests/test_functional.py b/plinth/modules/users/tests/test_functional.py index 063c7f548..d877ff81e 100644 --- a/plinth/modules/users/tests/test_functional.py +++ b/plinth/modules/users/tests/test_functional.py @@ -65,8 +65,9 @@ def test_create_user(session_browser): if functional.user_exists(session_browser, 'alice'): functional.delete_user(session_browser, 'alice') - functional.create_user(session_browser, 'alice') + functional.create_user(session_browser, 'alice', email='alice@example.com') assert functional.user_exists(session_browser, 'alice') + assert _get_email(session_browser, 'alice') == 'alice@example.com' def test_rename_user(session_browser): @@ -133,6 +134,17 @@ def test_users_cannot_connect_passwordless_over_ssh(session_browser, tmp_path_factory) +def test_update_user(session_browser): + """Test changing properties of a user.""" + functional.create_user(session_browser, 'alice', email='alice@example.com') + + # Update email + _set_email(session_browser, 'alice', 'alice1@example.com') + assert _get_email(session_browser, 'alice') == 'alice1@example.com' + _set_email(session_browser, 'alice', 'alice2@example.com') + assert _get_email(session_browser, 'alice') == 'alice2@example.com' + + @pytest.mark.parametrize('language_code', _language_codes.values()) def test_change_language(session_browser, language_code): """Test changing the language.""" @@ -254,6 +266,20 @@ def _rename_user(browser, old_name, new_name): functional.submit(browser, form_class='form-update') +def _set_email(browser, username, email): + """Set the email field value for a user.""" + functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username)) + browser.find_by_id('id_email').fill(email) + browser.find_by_id('id_confirm_password').fill(_admin_password) + functional.submit(browser, form_class='form-update') + + +def _get_email(browser, username): + """Return the email field value for a user.""" + functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username)) + return browser.find_by_id('id_email').value + + def _set_language(browser, language_code): username = functional.config['DEFAULT']['username'] functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username)) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index e4349cf42..c08d7753e 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -599,7 +599,7 @@ def get_forwarders(browser): ############################## -def create_user(browser, name, password=None, groups=[]): +def create_user(browser, name, password=None, groups=[], email=None): """Create a user with password and user groups.""" nav_to_module(browser, 'users') @@ -612,6 +612,8 @@ def create_user(browser, name, password=None, groups=[]): browser.find_by_id('id_username').fill(name) browser.find_by_id('id_password1').fill(password) browser.find_by_id('id_password2').fill(password) + if email: + browser.find_by_id('id_email').fill(email) for group in groups: browser.find_by_xpath( From 1b09d015752c541627fed550a10750127d095b9b Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 14 Mar 2024 10:55:01 -0700 Subject: [PATCH 41/63] users: Add email address field during first boot - Mostly because administrators won't discover the email address field for the user later on. - This field is important to be able to run 'reset password' operation. Tests: - In stable and testing containers, run first boot wizard. Enter the email address during the first boot and see that it was saved as part of user account. Leave the email address blank and it is possible to proceed. User account show blank email address. Signed-off-by: Sunil Mohan Adapa Reviewed-by: Veiko Aasa --- plinth/modules/users/forms.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py index 5f889bb48..e4297a662 100644 --- a/plinth/modules/users/forms.py +++ b/plinth/modules/users/forms.py @@ -382,11 +382,16 @@ class UserChangePasswordForm(PasswordConfirmForm, SetPasswordForm): return user -class FirstBootForm(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm): +class FirstBootForm(ValidNewUsernameCheckMixin, EmailFieldMixin, + auth.forms.UserCreationForm): """User module first boot step: create a new admin user.""" username = USERNAME_FIELD + class Meta(UserCreationForm.Meta): + """Metadata to control automatic form building.""" + fields = ('username', 'email', 'password1') + def __init__(self, *args, **kwargs): self.request = kwargs.pop('request') super().__init__(*args, **kwargs) @@ -399,6 +404,8 @@ class FirstBootForm(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm): """Create and log the user in.""" user = super().save(commit=commit) if commit: + self.save_m2m() # Django 3.x does not call save_m2m() + first_boot.mark_step_done('users_firstboot') try: From 6e557dd1e967bce6abd95fae00e1a2c57c605e1f Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 13 Mar 2024 22:59:04 -0700 Subject: [PATCH 42/63] system: Organize items into sections Closes: #2161. - Sections are ordered by importance on which administrator must act after setting up the system. - Consistent order across all the languages. - Update the styling for the section hearers. - For system section, make them compact. - Make them look like a header text (with underline) rather than a divider (like in a menu). Signed-off-by: Sunil Mohan Adapa Reviewed-by: Veiko Aasa --- plinth/menu.py | 12 ++++++++++++ plinth/modules/avahi/__init__.py | 3 ++- plinth/modules/backups/__init__.py | 3 ++- plinth/modules/bind/__init__.py | 2 +- plinth/modules/cockpit/__init__.py | 4 +++- plinth/modules/config/__init__.py | 3 ++- plinth/modules/datetime/__init__.py | 3 ++- plinth/modules/diagnostics/__init__.py | 4 +++- plinth/modules/dynamicdns/__init__.py | 3 ++- plinth/modules/firewall/__init__.py | 3 ++- plinth/modules/letsencrypt/__init__.py | 3 ++- plinth/modules/names/__init__.py | 3 ++- plinth/modules/networks/__init__.py | 3 ++- plinth/modules/pagekite/__init__.py | 3 ++- plinth/modules/performance/__init__.py | 4 +++- plinth/modules/power/__init__.py | 4 +++- plinth/modules/privacy/__init__.py | 3 ++- plinth/modules/security/__init__.py | 3 ++- plinth/modules/snapshot/__init__.py | 3 ++- plinth/modules/ssh/__init__.py | 4 +++- plinth/modules/storage/__init__.py | 3 ++- plinth/modules/upgrades/__init__.py | 3 ++- plinth/modules/users/__init__.py | 3 ++- plinth/templates/cards.html | 2 +- plinth/templates/system.html | 26 ++++++++++++++++++++++++++ plinth/urls.py | 12 +++++++++++- static/themes/default/css/main.css | 18 +++++++----------- 27 files changed, 105 insertions(+), 35 deletions(-) diff --git a/plinth/menu.py b/plinth/menu.py index fb1a561fa..a1d50110d 100644 --- a/plinth/menu.py +++ b/plinth/menu.py @@ -3,6 +3,7 @@ from typing import ClassVar from django.urls import reverse_lazy +from django.utils.translation import gettext_lazy as _ from plinth import app @@ -101,3 +102,14 @@ def init(): parent_url_name='index') Menu('menu-system', icon='fa-cog', url_name='system', parent_url_name='index') + + Menu('menu-system-visibility', name=_('Visibility'), icon='fa-cog', + url_name='system:visibility', parent_url_name='system', order=10) + Menu('menu-system-data', name=_('Data'), icon='fa-cog', + url_name='system:data', parent_url_name='system', order=20) + Menu('menu-system-system', name=_('System'), icon='fa-cog', + url_name='system:system', parent_url_name='system', order=30) + Menu('menu-system-security', name=_('Security'), icon='fa-cog', + url_name='system:security', parent_url_name='system', order=40) + Menu('menu-system-administration', name=_('Administration'), icon='fa-cog', + url_name='system:administration', parent_url_name='system', order=50) diff --git a/plinth/modules/avahi/__init__.py b/plinth/modules/avahi/__init__.py index 33c33ea49..8226a0bd4 100644 --- a/plinth/modules/avahi/__init__.py +++ b/plinth/modules/avahi/__init__.py @@ -50,7 +50,8 @@ class AvahiApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-avahi', info.name, None, info.icon, - 'avahi:index', parent_url_name='system') + 'avahi:index', + parent_url_name='system:visibility', order=50) self.add(menu_item) packages = Packages('packages-avahi', ['avahi-daemon', 'avahi-utils']) diff --git a/plinth/modules/backups/__init__.py b/plinth/modules/backups/__init__.py index 1944ce64c..5a6c6db19 100644 --- a/plinth/modules/backups/__init__.py +++ b/plinth/modules/backups/__init__.py @@ -47,7 +47,8 @@ class BackupsApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-backups', info.name, None, info.icon, - 'backups:index', parent_url_name='system') + 'backups:index', parent_url_name='system:data', + order=20) self.add(menu_item) packages = Packages('packages-backups', ['borgbackup', 'sshfs']) diff --git a/plinth/modules/bind/__init__.py b/plinth/modules/bind/__init__.py index 37c52b6df..4f4971731 100644 --- a/plinth/modules/bind/__init__.py +++ b/plinth/modules/bind/__init__.py @@ -44,7 +44,7 @@ class BindApp(app_module.App): menu_item = menu.Menu('menu-bind', info.name, info.short_description, info.icon, 'bind:index', - parent_url_name='system') + parent_url_name='system:visibility', order=30) self.add(menu_item) packages = Packages('packages-bind', ['bind9']) diff --git a/plinth/modules/cockpit/__init__.py b/plinth/modules/cockpit/__init__.py index 7d39c4d55..571d17419 100644 --- a/plinth/modules/cockpit/__init__.py +++ b/plinth/modules/cockpit/__init__.py @@ -59,7 +59,9 @@ class CockpitApp(app_module.App): menu_item = menu.Menu('menu-cockpit', info.name, info.short_description, info.icon, - 'cockpit:index', parent_url_name='system') + 'cockpit:index', + parent_url_name='system:administration', + order=20) self.add(menu_item) shortcut = frontpage.Shortcut('shortcut-cockpit', info.name, diff --git a/plinth/modules/config/__init__.py b/plinth/modules/config/__init__.py index 8a79e4666..fb28c948f 100644 --- a/plinth/modules/config/__init__.py +++ b/plinth/modules/config/__init__.py @@ -47,7 +47,8 @@ class ConfigApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-config', _('Configure'), None, info.icon, - 'config:index', parent_url_name='system') + 'config:index', parent_url_name='system:system', + order=30) self.add(menu_item) packages = Packages('packages-config', ['zram-tools']) diff --git a/plinth/modules/datetime/__init__.py b/plinth/modules/datetime/__init__.py index 052349009..4bc35802c 100644 --- a/plinth/modules/datetime/__init__.py +++ b/plinth/modules/datetime/__init__.py @@ -71,7 +71,8 @@ class DateTimeApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-datetime', info.name, None, info.icon, - 'datetime:index', parent_url_name='system') + 'datetime:index', + parent_url_name='system:system', order=40) self.add(menu_item) packages = Packages('packages-datetime', ['systemd-timesyncd']) diff --git a/plinth/modules/diagnostics/__init__.py b/plinth/modules/diagnostics/__init__.py index 9e9a56bc0..ff771de82 100644 --- a/plinth/modules/diagnostics/__init__.py +++ b/plinth/modules/diagnostics/__init__.py @@ -55,7 +55,9 @@ class DiagnosticsApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-diagnostics', info.name, None, info.icon, - 'diagnostics:index', parent_url_name='system') + 'diagnostics:index', + parent_url_name='system:administration', + order=30) self.add(menu_item) backup_restore = BackupRestore('backup-restore-diagnostics', diff --git a/plinth/modules/dynamicdns/__init__.py b/plinth/modules/dynamicdns/__init__.py index c257e246b..e0e0ec231 100644 --- a/plinth/modules/dynamicdns/__init__.py +++ b/plinth/modules/dynamicdns/__init__.py @@ -64,7 +64,8 @@ class DynamicDNSApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-dynamicdns', info.name, None, info.icon, - 'dynamicdns:index', parent_url_name='system') + 'dynamicdns:index', + parent_url_name='system:visibility', order=20) self.add(menu_item) enable_state = app_module.EnableState('enable-state-dynamicdns') diff --git a/plinth/modules/firewall/__init__.py b/plinth/modules/firewall/__init__.py index 2eb1c87ac..72a1f627e 100644 --- a/plinth/modules/firewall/__init__.py +++ b/plinth/modules/firewall/__init__.py @@ -64,7 +64,8 @@ class FirewallApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-firewall', info.name, None, info.icon, - 'firewall:index', parent_url_name='system') + 'firewall:index', + parent_url_name='system:security', order=30) self.add(menu_item) packages = Packages('packages-firewall', ['firewalld', 'nftables']) diff --git a/plinth/modules/letsencrypt/__init__.py b/plinth/modules/letsencrypt/__init__.py index 823bd4045..a27a14c09 100644 --- a/plinth/modules/letsencrypt/__init__.py +++ b/plinth/modules/letsencrypt/__init__.py @@ -66,7 +66,8 @@ class LetsEncryptApp(app_module.App): menu_item = menu.Menu('menu-letsencrypt', info.name, info.short_description, info.icon, - 'letsencrypt:index', parent_url_name='system') + 'letsencrypt:index', + parent_url_name='system:security', order=20) self.add(menu_item) packages = Packages('packages-letsencrypt', ['certbot']) diff --git a/plinth/modules/names/__init__.py b/plinth/modules/names/__init__.py index e6cf29247..1beaf06cc 100644 --- a/plinth/modules/names/__init__.py +++ b/plinth/modules/names/__init__.py @@ -46,7 +46,8 @@ class NamesApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-names', info.name, None, info.icon, - 'names:index', parent_url_name='system') + 'names:index', + parent_url_name='system:visibility', order=10) self.add(menu_item) backup_restore = BackupRestore('backup-restore-names', diff --git a/plinth/modules/networks/__init__.py b/plinth/modules/networks/__init__.py index df9e168d2..54371feda 100644 --- a/plinth/modules/networks/__init__.py +++ b/plinth/modules/networks/__init__.py @@ -62,7 +62,8 @@ class NetworksApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-networks', info.name, None, info.icon, - 'networks:index', parent_url_name='system') + 'networks:index', + parent_url_name='system:system', order=20) self.add(menu_item) packages = Packages('packages-networks', ['network-manager', 'batctl']) diff --git a/plinth/modules/pagekite/__init__.py b/plinth/modules/pagekite/__init__.py index 29e6b313f..033fd8a73 100644 --- a/plinth/modules/pagekite/__init__.py +++ b/plinth/modules/pagekite/__init__.py @@ -64,7 +64,8 @@ class PagekiteApp(app_module.App): menu_item = menu.Menu('menu-pagekite', info.name, info.short_description, info.icon, - 'pagekite:index', parent_url_name='system') + 'pagekite:index', + parent_url_name='system:visibility', order=40) self.add(menu_item) packages = Packages('packages-pagekite', ['pagekite']) diff --git a/plinth/modules/performance/__init__.py b/plinth/modules/performance/__init__.py index 4b681e1ec..59d1498f5 100644 --- a/plinth/modules/performance/__init__.py +++ b/plinth/modules/performance/__init__.py @@ -46,7 +46,9 @@ class PerformanceApp(app_module.App): menu_item = menu.Menu('menu-performance', info.name, info.short_description, info.icon, - 'performance:index', parent_url_name='system') + 'performance:index', + parent_url_name='system:administration', + order=40) self.add(menu_item) packages = Packages('packages-performance', ['cockpit-pcp']) diff --git a/plinth/modules/power/__init__.py b/plinth/modules/power/__init__.py index f80a936bd..3720c0212 100644 --- a/plinth/modules/power/__init__.py +++ b/plinth/modules/power/__init__.py @@ -34,7 +34,9 @@ class PowerApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-power', info.name, None, info.icon, - 'power:index', parent_url_name='system') + 'power:index', + parent_url_name='system:administration', + order=50) self.add(menu_item) backup_restore = BackupRestore('backup-restore-power', diff --git a/plinth/modules/privacy/__init__.py b/plinth/modules/privacy/__init__.py index 56170c12e..89343f93a 100644 --- a/plinth/modules/privacy/__init__.py +++ b/plinth/modules/privacy/__init__.py @@ -36,7 +36,8 @@ class PrivacyApp(app_module.App): menu_item = menu.Menu('menu-privacy', info.name, info.short_description, info.icon, - 'privacy:index', parent_url_name='system') + 'privacy:index', parent_url_name='system:data', + order=10) self.add(menu_item) packages = Packages('packages-privacy', ['popularity-contest', 'gpg']) diff --git a/plinth/modules/security/__init__.py b/plinth/modules/security/__init__.py index a9effe9b9..01ca1e84a 100644 --- a/plinth/modules/security/__init__.py +++ b/plinth/modules/security/__init__.py @@ -37,7 +37,8 @@ class SecurityApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-security', info.name, None, info.icon, - 'security:index', parent_url_name='system') + 'security:index', + parent_url_name='system:security', order=10) self.add(menu_item) packages = Packages('packages-security', ['fail2ban', 'debsecan']) diff --git a/plinth/modules/snapshot/__init__.py b/plinth/modules/snapshot/__init__.py index 5e1c215e7..f4cf52846 100644 --- a/plinth/modules/snapshot/__init__.py +++ b/plinth/modules/snapshot/__init__.py @@ -53,7 +53,8 @@ class SnapshotApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-snapshot', info.name, None, info.icon, - 'snapshot:index', parent_url_name='system') + 'snapshot:index', parent_url_name='system:data', + order=40) self.add(menu_item) packages = Packages('packages-snapshot', ['snapper']) diff --git a/plinth/modules/ssh/__init__.py b/plinth/modules/ssh/__init__.py index d4a8438db..29cbba45a 100644 --- a/plinth/modules/ssh/__init__.py +++ b/plinth/modules/ssh/__init__.py @@ -45,7 +45,9 @@ class SSHApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-ssh', info.name, None, info.icon, - 'ssh:index', parent_url_name='system') + 'ssh:index', + parent_url_name='system:administration', + order=10) self.add(menu_item) packages = Packages('packages-ssh', ['openssh-server']) diff --git a/plinth/modules/storage/__init__.py b/plinth/modules/storage/__init__.py index 4f7034193..dff8d60b2 100644 --- a/plinth/modules/storage/__init__.py +++ b/plinth/modules/storage/__init__.py @@ -48,7 +48,8 @@ class StorageApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-storage', info.name, None, info.icon, - 'storage:index', parent_url_name='system') + 'storage:index', parent_url_name='system:data', + order=30) self.add(menu_item) packages = Packages('packages-storage', diff --git a/plinth/modules/upgrades/__init__.py b/plinth/modules/upgrades/__init__.py index 82279d3f1..14e7a49c7 100644 --- a/plinth/modules/upgrades/__init__.py +++ b/plinth/modules/upgrades/__init__.py @@ -68,7 +68,8 @@ class UpgradesApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-upgrades', info.name, None, info.icon, - 'upgrades:index', parent_url_name='system') + 'upgrades:index', + parent_url_name='system:system', order=50) self.add(menu_item) packages = Packages('packages-upgrades', diff --git a/plinth/modules/users/__init__.py b/plinth/modules/users/__init__.py index 61b398c6a..021dffa5e 100644 --- a/plinth/modules/users/__init__.py +++ b/plinth/modules/users/__init__.py @@ -62,7 +62,8 @@ class UsersApp(app_module.App): self.add(info) menu_item = menu.Menu('menu-users', info.name, None, info.icon, - 'users:index', parent_url_name='system') + 'users:index', parent_url_name='system:system', + order=10) self.add(menu_item) packages = Packages('packages-users', [ diff --git a/plinth/templates/cards.html b/plinth/templates/cards.html index da19bdc3a..f5ba47d82 100644 --- a/plinth/templates/cards.html +++ b/plinth/templates/cards.html @@ -31,7 +31,7 @@ {% if show_disabled %}
-
{% trans "Disabled" %}
+
{% trans "Disabled" %}
{% for item in submenu.sorted_items %} diff --git a/plinth/templates/system.html b/plinth/templates/system.html index 126688808..7bef3e372 100644 --- a/plinth/templates/system.html +++ b/plinth/templates/system.html @@ -7,3 +7,29 @@ {% load i18n %} {% block body_class %}system-page{% endblock %} + +{% block container %} +
+
+
+ {% include 'messages.html' %} +
+
+
+ +
+ {% for section_item in submenu.sorted_items %} +
{{ section_item.name }}
+
+
+ {% for item in section_item.sorted_items %} + {% if advanced_mode or not item.advanced %} + {% include "card.html" %} + {% endif %} + {% endfor %} +
+
+ {% endfor %} +
+ +{% endblock %} diff --git a/plinth/urls.py b/plinth/urls.py index 34c61068c..c53710caf 100644 --- a/plinth/urls.py +++ b/plinth/urls.py @@ -3,11 +3,20 @@ Django URLconf file containing all urls """ from captcha import views as cviews -from django.urls import re_path +from django.urls import include, re_path from stronghold.decorators import public from . import views +system_urlpatterns = [ + re_path(r'^sys/#visibility$', views.system_index, name='visibility'), + re_path(r'^sys/#data$', views.system_index, name='data'), + re_path(r'^sys/#system$', views.system_index, name='system'), + re_path(r'^sys/#security$', views.system_index, name='security'), + re_path(r'^sys/#administration$', views.system_index, + name='administration'), +] + urlpatterns = [ re_path(r'^$', views.index, name='index'), re_path(r'^language-selection/$', @@ -15,6 +24,7 @@ urlpatterns = [ name='language-selection'), re_path(r'^apps/$', views.AppsIndexView.as_view(), name='apps'), re_path(r'^sys/$', views.system_index, name='system'), + re_path(r'', include((system_urlpatterns, 'system'))), re_path(r'^uninstall/(?P[1-9a-z\-_]+)/$', views.UninstallView.as_view(), name='uninstall'), re_path(r'^rerun-setup/(?P[1-9a-z\-_]+)/$', views.rerun_setup_view, diff --git a/static/themes/default/css/main.css b/static/themes/default/css/main.css index 5f6b2a94d..63c650658 100644 --- a/static/themes/default/css/main.css +++ b/static/themes/default/css/main.css @@ -488,20 +488,16 @@ footer { justify-content: left; } -.card-section-title { +.card-section-title, .system-section-title { display: flex; font-weight: 800; font-size: 1.25rem; - padding: 0 2.875rem; - margin: 1.25rem 0; + margin-bottom: 1.25rem; + border-bottom: var(--neutral-dark-color) solid 2px; } -.card-section-title:before, .card-section-title:after { - color: white; - content: ''; - flex: 1; - border-bottom: var(--neutral-dark-color) solid 2px; - margin: auto 1.125rem; +.card-section-title { + margin-top: 1.25rem; } a.menu_link { @@ -605,7 +601,7 @@ a.menu_link_active { /* Button table - Tables with a list of actions as buttons on top */ .index-page .card-list:before, .apps-page .card-list:before, -.system-page .card-list:before { +.system-page .system-section-title:first-child:before { position: relative; width: 25rem; height: 25rem; @@ -627,7 +623,7 @@ a.menu_link_active { background-image: url('../img/apps-background.svg'); } -.system-page .card-list:before { +.system-page .system-section-title:first-child:before { background-image: url('../img/system-background.svg'); } From 5b299068a8d462aad22ed9cc5e49a77a2e415a4d Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Mon, 11 Mar 2024 14:37:01 -0700 Subject: [PATCH 43/63] views: Fix alignment of close button in error messages Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/templates/messages.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plinth/templates/messages.html b/plinth/templates/messages.html index 9fe1932ff..95ae9847f 100644 --- a/plinth/templates/messages.html +++ b/plinth/templates/messages.html @@ -5,7 +5,7 @@ {% load i18n %} {% for message in messages %} -
+
{{ message }}