Merge branch 'master' into 'fantabular'

# Conflicts:
#   docs/maintenance/tuning/index.md
This commit is contained in:
Ariel Rin 2023-12-02 01:38:18 +00:00
commit 81e5bc5337
37 changed files with 1665 additions and 603 deletions

View File

@ -1,5 +1,5 @@
[main]
host = https://www.transifex.com
host = https://app.transifex.com
lang_map = zh-Hans: zh_Hans
[o:alliance-auth:p:alliance-auth:r:django-po]

View File

@ -1,10 +0,0 @@
[main]
host = https://www.transifex.com
lang_map = zh-Hans:zh_Hans
[alliance-auth.django-po]
file_filter = allianceauth/locale/<lang>/LC_MESSAGES/django.po
minimum_perc = 0
source_file = allianceauth/locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO

10
.tx/transifex.yml Normal file
View File

@ -0,0 +1,10 @@
filters:
- filter_type: file
file_format: PO
source_file: allianceauth/locale/en/LC_MESSAGES/django.po
source_language: en
translation_files_expression: allianceauth/locale/<lang>/LC_MESSAGES/django.po
settings:
language_mapping:
zh-Hans: zh_Hans

View File

@ -5,7 +5,7 @@ manage online service access.
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
__version__ = '3.7.1'
__version__ = '3.8.0'
__title__ = 'Alliance Auth'
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
NAME = f'{__title__} v{__version__}'

View File

@ -1,6 +1,10 @@
import functools
from django import forms
from django.contrib.auth.models import Group
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import Group, User
from django.core.exceptions import ValidationError
from django.db.models.functions import Lower
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
@ -8,6 +12,39 @@ from .models import ReservedGroupName
class GroupAdminForm(forms.ModelForm):
users = forms.ModelMultipleChoiceField(
queryset=User.objects.order_by(Lower('username')),
required=False,
widget=FilteredSelectMultiple(verbose_name=_("Users"), is_stacked=False),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance and self.instance.pk:
self.fields["users"].initial = self.instance.user_set.all()
def save(self, commit=True):
group: Group = super().save(commit=False)
if commit:
group.save()
users = self.cleaned_data["users"]
if group.pk:
self._save_m2m_and_users(group, users)
else:
self.save_m2m = functools.partial(
self._save_m2m_and_users, group=group, users=users
)
return group
def _save_m2m_and_users(self, group, users):
"""Save m2m relations incl. users."""
group.user_set.set(users)
self._save_m2m()
def clean_name(self):
my_name = self.cleaned_data['name']
if ReservedGroupName.objects.filter(name__iexact=my_name).exists():

View File

@ -1,8 +1,7 @@
from typing import Set
from django.conf import settings
from django.contrib.auth.models import Group
from django.contrib.auth.models import User
from django.contrib.auth.models import Group, User
from django.db import models
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
@ -14,7 +13,7 @@ from allianceauth.notifications import notify
class GroupRequest(models.Model):
"""Request from a user for joining or leaving a group."""
leave_request = models.BooleanField(default=0)
leave_request = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
@ -49,7 +48,7 @@ class RequestLog(models.Model):
request_type = models.BooleanField(null=True)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
request_info = models.CharField(max_length=254)
action = models.BooleanField(default=0)
action = models.BooleanField(default=False)
request_actor = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)

View File

@ -29,7 +29,7 @@
</a>
</li>
{% if not auto_leave %}
{% if not show_leave_tab %}
<li>
<a data-toggle="tab" href="#leave">
{% translate "Leave Requests" %}
@ -102,7 +102,7 @@
{% endif %}
</div>
{% if not auto_leave %}
{% if not show_leave_tab %}
<div id="leave" class="tab-pane">
{% if leaverequests %}
<div class="table-responsive">

View File

@ -6,22 +6,22 @@ from django.conf import settings
from django.contrib import admin
from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import User
from django.test import TestCase, RequestFactory, Client, override_settings
from django.test import Client, RequestFactory, TestCase, override_settings
from allianceauth.authentication.models import CharacterOwnership, State
from allianceauth.eveonline.models import (
EveCharacter, EveCorporationInfo, EveAllianceInfo
EveAllianceInfo, EveCharacter, EveCorporationInfo,
)
from allianceauth.tests.auth_utils import AuthUtils
from . import get_admin_change_view_url
from ..admin import HasLeaderFilter, GroupAdmin, Group
from ..admin import Group, GroupAdmin, HasLeaderFilter
from ..models import ReservedGroupName
from . import get_admin_change_view_url
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
_has_auto_groups = True
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
from ..admin import IsAutoGroupFilter
else:
_has_auto_groups = False
@ -621,21 +621,16 @@ class TestGroupAdmin2(TestCase):
response = self.client.post(
f"/admin/groupmanagement/group/{group.pk}/change/",
data={
"name": f"{group.name}",
"authgroup-TOTAL_FORMS": "1",
"authgroup-INITIAL_FORMS": "1",
"authgroup-MIN_NUM_FORMS": "0",
"authgroup-MAX_NUM_FORMS": "1",
"authgroup-0-description": "",
"authgroup-0-states": f"{member_state.pk}",
"name": group.name,
"users": [user_member.pk, user_guest.pk],
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 1,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
"authgroup-0-states": member_state.pk,
"authgroup-0-internal": "on",
"authgroup-0-hidden": "on",
"authgroup-0-group": f"{group.pk}",
"authgroup-__prefix__-description": "",
"authgroup-__prefix__-internal": "on",
"authgroup-__prefix__-hidden": "on",
"authgroup-__prefix__-group": f"{group.pk}",
"_save": "Save"
"authgroup-0-group": group.pk,
}
)
# then
@ -644,6 +639,85 @@ class TestGroupAdmin2(TestCase):
self.assertIn(group, user_member.groups.all())
self.assertNotIn(group, user_guest.groups.all())
def test_should_add_user_to_existing_group(self):
# given
user_bruce = AuthUtils.create_user("Bruce Wayne")
user_lex = AuthUtils.create_user("Lex Luthor")
group = Group.objects.create(name="dummy")
user_bruce.groups.add(group)
self.client.force_login(self.superuser)
# when
response = self.client.post(
f"/admin/groupmanagement/group/{group.pk}/change/",
data={
"name": group.name,
"users": [user_bruce.pk, user_lex.pk],
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 1,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
"authgroup-0-internal": "on",
"authgroup-0-hidden": "on",
"authgroup-0-group": group.pk,
}
)
# then
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/groupmanagement/group/")
self.assertIn(group, user_bruce.groups.all())
self.assertIn(group, user_lex.groups.all())
def test_should_remove_user_from_existing_group(self):
# given
user_bruce = AuthUtils.create_user("Bruce Wayne")
user_lex = AuthUtils.create_user("Lex Luthor")
group = Group.objects.create(name="dummy")
user_bruce.groups.add(group)
user_lex.groups.add(group)
self.client.force_login(self.superuser)
# when
response = self.client.post(
f"/admin/groupmanagement/group/{group.pk}/change/",
data={
"name": group.name,
"users": user_bruce.pk,
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 1,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
"authgroup-0-internal": "on",
"authgroup-0-hidden": "on",
"authgroup-0-group": group.pk,
}
)
# then
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/groupmanagement/group/")
self.assertIn(group, user_bruce.groups.all())
self.assertNotIn(group, user_lex.groups.all())
def test_should_include_user_when_creating_group(self):
# given
user_bruce = AuthUtils.create_user("Bruce Wayne")
self.client.force_login(self.superuser)
# when
response = self.client.post(
"/admin/groupmanagement/group/add/",
data={
"name": "new group",
"users": user_bruce.pk,
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 0,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
}
)
# then
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/groupmanagement/group/")
group = Group.objects.get(name="new group")
self.assertIn(group, user_bruce.groups.all())
class TestReservedGroupNameAdmin(TestCase):
@classmethod

View File

@ -1,6 +1,7 @@
from django.test import RequestFactory, TestCase, override_settings
from django.urls import reverse
from allianceauth.groupmanagement.models import Group, GroupRequest
from allianceauth.tests.auth_utils import AuthUtils
from .. import views
@ -16,6 +17,7 @@ class TestViews(TestCase):
self.factory = RequestFactory()
self.user = AuthUtils.create_user('Peter Parker')
self.user_with_manage_permission = AuthUtils.create_user('Bruce Wayne')
self.group = Group.objects.create(name="Example group")
# set permissions
AuthUtils.add_permission_to_user_by_name(
@ -83,3 +85,19 @@ class TestViews(TestCase):
self.assertEqual(response.status_code, 200)
self.assertNotIn('<a data-toggle="tab" href="#leave">', content)
self.assertNotIn('<div id="leave" class="tab-pane">', content)
@override_settings(GROUPMANAGEMENT_AUTO_LEAVE=True)
def test_should_not_hide_leave_requests_tab_when_there_are_open_requests(self):
# given
request = self.factory.get(reverse('groupmanagement:management'))
request.user = self.user_with_manage_permission
GroupRequest.objects.create(user=self.user, group=self.group, leave_request=True)
# when
response = views.group_management(request)
# then
content = response_content_to_str(response)
self.assertEqual(response.status_code, 200)
self.assertIn('<a data-toggle="tab" href="#leave">', content)
self.assertIn('<div id="leave" class="tab-pane">', content)

View File

@ -2,13 +2,12 @@ import logging
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import Group
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db.models import Count
from django.http import Http404
from django.shortcuts import render, redirect, get_object_or_404
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.translation import gettext_lazy as _
from allianceauth.notifications import notify
@ -16,7 +15,6 @@ from allianceauth.notifications import notify
from .managers import GroupManager
from .models import GroupRequest, RequestLog
logger = logging.getLogger(__name__)
@ -45,10 +43,15 @@ def group_management(request):
logger.debug("Providing user {} with {} acceptrequests and {} leaverequests.".format(
request.user, len(acceptrequests), len(leaverequests)))
show_leave_tab = (
getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False)
and not GroupRequest.objects.filter(leave_request=True).exists()
)
render_items = {
'acceptrequests': acceptrequests,
'leaverequests': leaverequests,
'auto_leave': getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False),
'show_leave_tab': show_leave_tab,
}
return render(request, 'groupmanagement/index.html', context=render_items)

View File

@ -4,9 +4,9 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Erik Kalkoken <erik.kalkoken@gmail.com>, 2020
# Joel Falknau <ozirascal@gmail.com>, 2021
# Peter Pfeufer, 2022
# Erik Kalkoken <erik.kalkoken@gmail.com>, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
# Peter Pfeufer, 2023
#
#, fuzzy
msgid ""
@ -14,8 +14,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: Peter Pfeufer, 2022\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: Peter Pfeufer, 2023\n"
"Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -34,7 +34,8 @@ msgstr "Google Analytics V4"
#: allianceauth/authentication/decorators.py:37
msgid "A main character is required to perform that action. Add one below."
msgstr ""
"Für diese Aktion wird ein Hauptcharacter benötigt. Bitte füge einen hinzu."
"Zur Ausführung dieser Aktion ist ein Hauptcharakter erforderlich. Füge unten"
" einen hinzu."
#: allianceauth/authentication/forms.py:12
msgid "Email"
@ -131,7 +132,7 @@ msgstr "Hauptcharakter ändern"
#: allianceauth/authentication/templates/authentication/dashboard.html:125
msgid "Group Memberships"
msgstr "Gruppen"
msgstr "Gruppenmitgliedschaften"
#: allianceauth/authentication/templates/authentication/dashboard.html:145
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:21
@ -206,7 +207,7 @@ msgstr ""
#: allianceauth/authentication/views.py:83
#, python-format
msgid "Changed main character to %(char)s"
msgstr "Haupcharakter geändert zu %(char)s"
msgstr "Haupcharakter zu %(char)s geändert"
#: allianceauth/authentication/views.py:92
#, python-format
@ -233,13 +234,12 @@ msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
msgstr ""
"Bestätigungsmail gesendet. Bitte folge dem Link in der E-Mail zur "
"Bestätigung."
"Bestätigungs-E-Mail gesendet. Bitte folge dem Link, um Deine E-Mail-Adresse "
"zu bestätigen."
#: allianceauth/authentication/views.py:257
msgid "Confirmed your email address. Please login to continue."
msgstr ""
"Deine E-Mail Adresse wurde bestätigt. Bitte log Dich ein um fortzufahren."
msgstr "Deine E-Mail Adresse wurde bestätigt. Bitte einloggen zum Fortfahren."
#: allianceauth/authentication/views.py:262
msgid "Registration of new accounts is not allowed at this time."
@ -274,7 +274,7 @@ msgstr "Hauptcharaktere"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:22
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:14
msgid "Members"
msgstr "Mitgliederzahl"
msgstr "Mitglieder"
#: allianceauth/corputils/templates/corputils/corpstats.html:35
msgid "Unregistered"
@ -282,7 +282,7 @@ msgstr "Nicht registriert"
#: allianceauth/corputils/templates/corputils/corpstats.html:38
msgid "Last update:"
msgstr "Letzes Update:"
msgstr "Letzte Aktualisierung:"
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
@ -382,11 +382,11 @@ msgstr "Charakter nicht registriert!"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
msgid "This character is not associated with an auth account."
msgstr "Dieser Charakter ist mit keinen Auth Konto verbunden."
msgstr "Dieser Charakter ist keinem Auth Konto zugeordnet."
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
msgid "Add it here"
msgstr "Füge es hier hinzu"
msgstr "Füge ihn hier hinzu"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
msgid "before attempting to click fleet attendance links."
@ -394,7 +394,7 @@ msgstr "bevor Du versuchst auf FAT-Links zu klicken."
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:5
msgid "Create Fatlink"
msgstr "Erstelle FAT-Link"
msgstr "FAT-Link erstellen"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:9
#: allianceauth/optimer/templates/optimer/add.html:13
@ -409,20 +409,20 @@ msgstr "Fehlerhafte Anfrage!"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:24
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:63
msgid "Create fatlink"
msgstr "Erstelle FAT-Link"
msgstr "FAT-Link erstellen"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:3
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:4
msgid "Fatlink view"
msgstr "FAT-Link sehen"
msgstr "FAT-Link ansehen"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:7
msgid "Edit fatlink"
msgstr "Editiere FAT-Link"
msgstr "FAT-Link bearbeiten"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:11
msgid "Delete fat"
msgstr "Lösche FAT"
msgstr "FAT löschen"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:17
msgid "Registered characters"
@ -497,7 +497,7 @@ msgstr[1] "%(user)s hat diesen Monat %(links)s FAT-Links eingesammelt."
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:26
msgid "Times used"
msgstr "male genutzt"
msgstr "Wie oft genutzt"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:37
#, python-format
@ -570,7 +570,7 @@ msgstr "FAT-Link Statistik"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20
msgid "Ticker"
msgstr "Ticker: "
msgstr "Ticker"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:8
msgid "Participation data"
@ -594,7 +594,7 @@ msgstr "Letzter FAT-Link"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:58
msgid "View statistics"
msgstr "Statistik"
msgstr "Statistiken ansehen"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:95
msgid "No created fatlinks on record."
@ -713,8 +713,8 @@ msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
msgstr ""
"Hier gelistete Ränge können dieser Gruppe beitreten, vorausgesetzt sie haben"
" die entsprechenden Berechtigungen.<br>"
"Die hier aufgeführten Status können dieser Gruppe beitreten, sofern sie über"
" die entsprechenden Berechtigungen verfügen.<br>"
#: allianceauth/groupmanagement/models.py:171
msgid ""
@ -814,7 +814,7 @@ msgstr "Gruppenmitglieder"
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:113
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:21
msgid "Organization"
msgstr "Organization"
msgstr "Organisation"
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:49
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:75
@ -933,18 +933,18 @@ msgstr "Gruppenverwaltung"
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:24
msgid "Join Requests"
msgstr "Beitrittsgesuche"
msgstr "Beitrittsanfragen"
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:35
msgid "Leave Requests"
msgstr "Austrittsgesuche"
msgstr "Austrittsanfragen"
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:57
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:114
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:18
#: allianceauth/services/modules/openfire/forms.py:6
msgid "Group"
msgstr "Gruppen"
msgstr "Gruppe"
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:88
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:145
@ -968,7 +968,7 @@ msgstr "Keine Gruppenaustrittsanfragen"
#: allianceauth/groupmanagement/templates/groupmanagement/menu.html:8
#: allianceauth/templates/allianceauth/top-menu.html:8
msgid "Toggle navigation"
msgstr "Toggle Navigation"
msgstr "Navigation umschalten"
#: allianceauth/groupmanagement/templates/groupmanagement/menu.html:19
msgid "Group Requests"
@ -994,7 +994,7 @@ msgstr "Gruppe existiert nicht"
#: allianceauth/groupmanagement/views.py:195
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s zugestimmt."
msgstr "Beitrittsanfrage von %(mainchar)s zur Gruppe %(group)s akzeptiert."
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
@ -1003,18 +1003,18 @@ msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to %(group)s."
msgstr ""
"Bei der Bearbeitung des Beitrittsgesuchs von %(mainchar)s zur Gruppe "
"Bei der Bearbeitung des Beitrittsanfrage von %(mainchar)s zur Gruppe "
"%(group)s ist ein unbehandelter Fehler aufgetreten."
#: allianceauth/groupmanagement/views.py:226
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s abgelehnt."
msgstr "Beitrittsanfrage von %(mainchar)s zur Gruppe %(group)s abgelehnt."
#: allianceauth/groupmanagement/views.py:261
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s akzeptiert."
msgstr "Austrittsanfrage von %(mainchar)s für Gruppe %(group)s akzeptiert."
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
@ -1023,13 +1023,13 @@ msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to leave %(group)s."
msgstr ""
"Bei der Bearbeitung des Austrittsgesuchs von %(mainchar)s für Gruppe "
"Bei der Bearbeitung des Austrittsanfrage von %(mainchar)s für Gruppe "
"%(group)s ist ein unbehandelter Fehler aufgetreten."
#: allianceauth/groupmanagement/views.py:292
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s abgelehnt."
msgstr "Austrittsanfrage von %(mainchar)s für Gruppe %(group)s abgelehnt."
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
@ -1042,7 +1042,7 @@ msgstr "Du bist bereits Mitglied dieser Gruppe."
#: allianceauth/groupmanagement/views.py:358
msgid "You already have a pending application for that group."
msgstr "Du hast Dich bereits für diese Gruppe beworben."
msgstr "Du hast bereits für diese Gruppe angefragt."
#: allianceauth/groupmanagement/views.py:367
#, python-format
@ -1059,12 +1059,12 @@ msgstr "Du bist kein Mitglied dieser Gruppe"
#: allianceauth/groupmanagement/views.py:393
msgid "You already have a pending leave request for that group."
msgstr "Du hast bereits ein ausstehendes Austrittsgesuch für diese Gruppe."
msgstr "Du hast bereits eine ausstehendes Austrittsanfrage für diese Gruppe."
#: allianceauth/groupmanagement/views.py:409
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "Austrittsgesuch für Gruppe %(group)s gesendet."
msgstr "Austrittsanfrage für Gruppe %(group)s gesendet."
#: allianceauth/hrapplications/auth_hooks.py:14
msgid "Applications"
@ -1086,11 +1086,11 @@ msgstr "Wähle eine Corporation"
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:10
msgid "Available Corps"
msgstr "Zur Auswahl stehende Corporations"
msgstr "Verfügbare Corporationen"
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:22
msgid "No corps are accepting applications at this time."
msgstr "Zur Zeit nimmt keine Corp Bewerbungen entgegen."
msgstr "Zur Zeit nimmt keine Corp Bewerbungen an."
#: allianceauth/hrapplications/templates/hrapplications/create.html:4
#: allianceauth/hrapplications/templates/hrapplications/create.html:7
@ -1186,7 +1186,7 @@ msgstr "Keine angesehenen Bewerbungen"
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:62
#: allianceauth/hrapplications/templates/hrapplications/view.html:134
msgid "Close"
msgstr "Geschlossen"
msgstr "Schließen"
#: allianceauth/hrapplications/templates/hrapplications/management.html:177
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:63
@ -1200,7 +1200,7 @@ msgstr "Suche"
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:11
msgid "Application Search Results"
msgstr "Bewerbungen Suchergebnisse"
msgstr "Ergebnisse der Bewerbungssuche"
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:22
msgid "Application ID"
@ -1342,12 +1342,12 @@ msgstr "Operationsart"
#: allianceauth/optimer/form.py:17
#: allianceauth/srp/templates/srp/management.html:38
msgid "Fleet Commander"
msgstr "Flottenkommandeur"
msgstr "Flottenkommandant"
#: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14
#: allianceauth/srp/templates/srp/data.html:91
msgid "Additional Info"
msgstr "Zusätzliche Info"
msgstr "Zusätzliche Informationen"
#: allianceauth/optimer/form.py:23
msgid "(Optional) Describe the operation with a couple of short words."
@ -1360,7 +1360,7 @@ msgstr "Operation erstellen"
#: allianceauth/optimer/templates/optimer/fleetoptable.html:12
msgid "Form Up System"
msgstr "Form Up System"
msgstr "Startsystem"
#: allianceauth/optimer/templates/optimer/fleetoptable.html:14
#: allianceauth/timerboard/templates/timerboard/view.html:36
@ -1384,20 +1384,20 @@ msgstr "Flottenoperationen Zeiten"
#: allianceauth/optimer/templates/optimer/management.html:20
#: allianceauth/timerboard/templates/timerboard/view.html:22
msgid "Current Eve Time:"
msgstr "Momentane Eve Zeit"
msgstr "Aktuelle Eve Zeit"
#: allianceauth/optimer/templates/optimer/management.html:26
msgid "Next Fleet Operations"
msgstr "Anstehende Flottenoperationen"
msgstr "Anstehende Flotten"
#: allianceauth/optimer/templates/optimer/management.html:30
#: allianceauth/timerboard/templates/timerboard/view.html:362
msgid "No upcoming timers."
msgstr "Keine kommenden Timer."
msgstr "Keine bevorstehenden Timer."
#: allianceauth/optimer/templates/optimer/management.html:33
msgid "Past Fleet Operations"
msgstr "Vergangene Flottenoperationen"
msgstr "Vergangene Flotten"
#: allianceauth/optimer/templates/optimer/management.html:37
#: allianceauth/timerboard/templates/timerboard/view.html:535
@ -1408,7 +1408,7 @@ msgstr "Keine vergangenen Timer."
#: allianceauth/optimer/templates/optimer/update.html:15
#: allianceauth/optimer/templates/optimer/update.html:27
msgid "Update Fleet Operation"
msgstr "Aktualisiere Flottenoperationen"
msgstr "Aktualisiere Flottenoperation"
#: allianceauth/optimer/templates/optimer/update.html:21
msgid "Fleet Operation Does Not Exist"
@ -1432,7 +1432,7 @@ msgstr "Änderungen für Operation timer %(opname)s gespeichert."
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:4
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:8
msgid "Permissions Audit"
msgstr "Berechtigungsübersicht"
msgstr "Berechtigungsprüfung"
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:20
msgid "User / Character"
@ -1494,11 +1494,11 @@ msgstr "Dienste"
#: allianceauth/services/forms.py:6
msgid "Name of Fleet:"
msgstr "SRP Flotte erstellen:"
msgstr "Name der Flotte:"
#: allianceauth/services/forms.py:7
msgid "Fleet Commander:"
msgstr "Flottenkommandeur:"
msgstr "Flottenkommandant:"
#: allianceauth/services/forms.py:8
msgid "Fleet Comms:"
@ -1514,11 +1514,11 @@ msgstr "Schiffspriorität:"
#: allianceauth/services/forms.py:11
msgid "Formup Location:"
msgstr "Formup Location:"
msgstr "Startsystem:"
#: allianceauth/services/forms.py:12
msgid "Formup Time:"
msgstr "Formup Zeit:"
msgstr "Startzeit:"
#: allianceauth/services/forms.py:13
msgid "Expected Duration:"
@ -1530,7 +1530,7 @@ msgstr "Grund:"
#: allianceauth/services/forms.py:15
msgid "Reimbursable?*"
msgstr "Erstattungsfähig?"
msgstr "Erstattungsfähig?*"
#: allianceauth/services/forms.py:15 allianceauth/services/forms.py:16
msgid "Yes"
@ -1542,7 +1542,7 @@ msgstr "Nein"
#: allianceauth/services/forms.py:16
msgid "Important?*"
msgstr "Wichtig?"
msgstr "Wichtig?*"
#: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31
msgid "Password"
@ -1550,7 +1550,7 @@ msgstr "Passwort"
#: allianceauth/services/forms.py:26 allianceauth/services/forms.py:36
msgid "Password must be at least 8 characters long."
msgstr "Passwort muss mindestens 8 Zeichen lang sein"
msgstr "Das Passwort muss mindestens 8 Zeichen lang sein"
#: allianceauth/services/modules/discord/models.py:187
msgid "Discord Account Disabled"
@ -1591,7 +1591,7 @@ msgstr "Discord Konto deaktiviert."
#: allianceauth/services/modules/discord/views.py:36
#: allianceauth/services/modules/discord/views.py:59
msgid "An error occurred while processing your Discord account."
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Discord Kontos."
msgstr "Es gab einen Fehler während der Verarbeitung Deines Discord Kontos."
#: allianceauth/services/modules/discord/views.py:102
msgid "Your Discord account has been successfully activated."
@ -1607,7 +1607,7 @@ msgstr ""
#: allianceauth/services/modules/discourse/views.py:29
msgid "You are not authorized to access Discourse."
msgstr "Du bist nicht autorisiert auf Discorse zuzugreifen."
msgstr "Du bist nicht autorisiert auf Discourse zuzugreifen."
#: allianceauth/services/modules/discourse/views.py:34
msgid "You must have a main character set to access Discourse."
@ -1619,14 +1619,14 @@ msgid ""
"No SSO payload or signature. Please contact support if this problem "
"persists."
msgstr ""
"Keine SSO-Nutzdaten oder Signaturen. Bitte wenden Sie sich an den Support, "
"wenn das Problem weiterhin besteht."
"Keine SSO-Nutzdaten oder Signaturen. Bitte wende Dich an den Support, wenn "
"das Problem weiterhin besteht."
#: allianceauth/services/modules/discourse/views.py:54
#: allianceauth/services/modules/discourse/views.py:62
msgid "Invalid payload. Please contact support if this problem persists."
msgstr ""
"Ungültige Nutzdaten. Bitte wenden Sie sich an den Support, wenn das Problem "
"Ungültige Nutzdaten. Bitte wenden Dich an den Support, wenn das Problem "
"weiterhin besteht."
#: allianceauth/services/modules/ips4/views.py:31
@ -1638,7 +1638,7 @@ msgstr "IP4Suite Konto aktiviert."
#: allianceauth/services/modules/ips4/views.py:81
#: allianceauth/services/modules/ips4/views.py:101
msgid "An error occurred while processing your IPSuite4 account."
msgstr "Es gab einen Fehler bei der Verarbeitung Deines IPSuite4 Kontos."
msgstr "Es gab einen Fehler während der Verarbeitung Deines IPSuite4 Kontos."
#: allianceauth/services/modules/ips4/views.py:52
msgid "Reset IPSuite4 password."
@ -1660,7 +1660,7 @@ msgstr "Jabber"
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:5
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:10
msgid "Jabber Broadcast"
msgstr "Jabber Übertragung"
msgstr "Jabber Ankündigung"
#: allianceauth/services/modules/openfire/auth_hooks.py:94
msgid "Fleet Broadcast Formatter"
@ -1672,11 +1672,11 @@ msgstr "Nachricht"
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:16
msgid "Broadcast Sent!!"
msgstr "Übertragung gesendet!!"
msgstr "Ankündigung gesendet!!"
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:22
msgid "Broadcast"
msgstr "Übertragungen"
msgstr "Ankündigung"
#: allianceauth/services/modules/openfire/views.py:35
msgid "Activated jabber account."
@ -1687,7 +1687,7 @@ msgstr "Jabber Konto aktiviert."
#: allianceauth/services/modules/openfire/views.py:76
#: allianceauth/services/modules/openfire/views.py:147
msgid "An error occurred while processing your jabber account."
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Jabber Kontos."
msgstr "Es gab einen Fehler während der Verarbeitung Deines Jabber Kontos."
#: allianceauth/services/modules/openfire/views.py:69
msgid "Reset jabber password."
@ -1696,7 +1696,7 @@ msgstr "Jabber Passwort zurücksetzen."
#: allianceauth/services/modules/openfire/views.py:115
#, python-format
msgid "Sent jabber broadcast to %s"
msgstr "Sende Jabber Durchsage an %s"
msgstr "Sende Jabber Ankündigung an %s"
#: allianceauth/services/modules/openfire/views.py:144
msgid "Set jabber password."
@ -1711,7 +1711,7 @@ msgstr "Forum Konto aktiviert."
#: allianceauth/services/modules/phpbb3/views.py:78
#: allianceauth/services/modules/phpbb3/views.py:101
msgid "An error occurred while processing your forum account."
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Forum Kontos."
msgstr "Es gab einen Fehler während der Verarbeitung Deines Forum Kontos."
#: allianceauth/services/modules/phpbb3/views.py:53
msgid "Deactivated forum account."
@ -1734,7 +1734,7 @@ msgstr "SMF Konto aktiviert."
#: allianceauth/services/modules/smf/views.py:102
#: allianceauth/services/modules/smf/views.py:124
msgid "An error occurred while processing your SMF account."
msgstr "Es gab einen Fehler bei der Verarbeitung Deines SMF Kontos."
msgstr "Es gab einen Fehler während der Verarbeitung Deines SMF Kontos."
#: allianceauth/services/modules/smf/views.py:78
msgid "Deactivated SMF account."
@ -1751,7 +1751,7 @@ msgstr "Setze SMF Passwort."
#: allianceauth/services/modules/teamspeak3/forms.py:14
#, python-format
msgid "Unable to locate user %s on server"
msgstr "Kann den Benutzer %s auf dem Server nicht finden"
msgstr "Der Benutzer %s konnte auf dem Server nicht gefunden werden"
#: allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html:8
msgid "Update TS3 groups"
@ -1783,7 +1783,8 @@ msgstr "TeamSpeak3 Konto aktiviert."
#: allianceauth/services/modules/teamspeak3/views.py:74
#: allianceauth/services/modules/teamspeak3/views.py:100
msgid "An error occurred while processing your TeamSpeak3 account."
msgstr "Es gab einen Fehler bei der Verarbeitung Deines TeamSpeak3 Kontos."
msgstr ""
"Es gab einen Fehler während der Verarbeitung Deines TeamSpeak3 Kontos."
#: allianceauth/services/modules/teamspeak3/views.py:71
msgid "Deactivated TeamSpeak3 account."
@ -1802,7 +1803,7 @@ msgstr "XenForo Konto aktiviert."
#: allianceauth/services/modules/xenforo/views.py:73
#: allianceauth/services/modules/xenforo/views.py:94
msgid "An error occurred while processing your XenForo account."
msgstr "Es gab einen Fehler bei der Verarbeitung Deines XenForo Kontos."
msgstr "Es gab einen Fehler während der Verarbeitung Deines XenForo Kontos."
#: allianceauth/services/modules/xenforo/views.py:50
msgid "Deactivated XenForo account."
@ -1832,7 +1833,7 @@ msgstr "Formatieren"
#: allianceauth/services/templates/services/service_confirm_delete.html:12
#, python-format
msgid "Delete %(service_name)s Account?"
msgstr "Konto %(service_name)s löschen?"
msgstr " %(service_name)s Konto löschen?"
#: allianceauth/services/templates/services/service_confirm_delete.html:20
#, python-format
@ -1856,7 +1857,7 @@ msgstr "%(service_name)s Passwort ändern"
#: allianceauth/services/templates/services/service_password.html:9
#, python-format
msgid "Set %(service_name)s Password"
msgstr "%(service_name)s Passwort"
msgstr "%(service_name)s Passwort setzen"
#: allianceauth/services/templates/services/service_password.html:17
msgid "Set Password"
@ -1927,7 +1928,7 @@ msgstr "SRP Flotten Daten"
#: allianceauth/srp/templates/srp/data.html:50
msgid "SRP Fleet Data"
msgstr "SRP-Flotte Daten"
msgstr "SRP Flotte Daten"
#: allianceauth/srp/templates/srp/data.html:55
msgid "Mark Incomplete"
@ -2005,7 +2006,7 @@ msgstr "Füge SRP Flotte hinzu"
#: allianceauth/srp/templates/srp/management.html:39
msgid "Fleet AAR"
msgstr "Flotten AAR"
msgstr "Flottenbericht"
#: allianceauth/srp/templates/srp/management.html:40
msgid "Fleet SRP Code"
@ -2033,7 +2034,7 @@ msgstr "Deaktiviert"
#: allianceauth/srp/templates/srp/management.html:83
msgid "Completed"
msgstr "Fertig"
msgstr "Abgeschlossen"
#: allianceauth/srp/templates/srp/management.html:101
msgid "Are you sure you want to delete this SRP code and its contents?"
@ -2086,7 +2087,7 @@ msgstr "SRP Link für %(fleetname)s aktiviert."
#: allianceauth/srp/views.py:140
#, python-format
msgid "Marked SRP fleet %(fleetname)s as completed."
msgstr "SRP Flotte %(fleetname)s als vollständig markiert."
msgstr "SRP Flotte %(fleetname)s als abgeschlossen markiert."
#: allianceauth/srp/views.py:153
#, python-format
@ -2204,7 +2205,7 @@ msgstr "Testversion verfügbar"
#: allianceauth/templates/allianceauth/admin-status/overview.html:78
msgid "Task Queue"
msgstr "Warteschlange"
msgstr "Task-Warteschlange"
#: allianceauth/templates/allianceauth/admin-status/overview.html:81
#, python-format
@ -2249,7 +2250,7 @@ msgstr "Ausloggen"
#: allianceauth/timerboard/form.py:53
msgid "Other"
msgstr "anderes"
msgstr "Anderes"
#: allianceauth/timerboard/form.py:54
#: allianceauth/timerboard/templates/timerboard/view.html:62
@ -2353,7 +2354,7 @@ msgstr "Timer löschen"
#: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:19
#, python-format
msgid "Are you sure you want to delete timer \"%(object)s\"?"
msgstr "Bist Du sicher das Du Timer \"%(object)s\" löschen möchtest?"
msgstr "Bist Du sicher das Du Timer „%(object)s“ löschen möchtest?"
#: allianceauth/timerboard/templates/timerboard/timer_create_form.html:5
#: allianceauth/timerboard/templates/timerboard/timer_create_form.html:13

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"POT-Creation-Date: 2023-11-08 23:55+1000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -26,7 +26,7 @@ msgstr ""
msgid "Google Analytics V4"
msgstr ""
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr ""
@ -39,63 +39,68 @@ msgstr ""
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr ""
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr ""
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr ""
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr ""
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr ""
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr ""
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr ""
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr ""
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr ""
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr ""
#: allianceauth/authentication/models.py:91
msgid "Language"
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr ""
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr ""
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr ""
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr ""
@ -151,8 +156,49 @@ msgstr ""
msgid "Alliance"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on https://community.eveonline.com/support/"
"third-party-applications/ where possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr ""
@ -184,47 +230,47 @@ msgstr ""
msgid "Invalid or expired activation link."
msgstr ""
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
"account."
msgstr ""
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr ""
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr ""
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr ""
#: allianceauth/authentication/views.py:133
#: allianceauth/authentication/views.py:174
msgid "Unable to authenticate as the selected character."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:238
msgid "Registration token has expired."
msgstr ""
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:296
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
msgstr ""
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:301
msgid "Confirmed your email address. Please login to continue."
msgstr ""
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:306
msgid "Registration of new accounts is not allowed at this time."
msgstr ""
@ -267,19 +313,6 @@ msgstr ""
msgid "Last update:"
msgstr ""
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr ""
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@ -611,36 +644,41 @@ msgstr ""
msgid "Group Management"
msgstr ""
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr ""
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr ""
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr ""
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr ""
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this group."
"<br>Used for groups such as Members, Corp_*, Alliance_* etc.<br><b>Overrides "
"Hidden and Open options when selected.</b>"
msgstr ""
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
msgstr ""
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@ -648,65 +686,65 @@ msgid ""
"authenticated."
msgstr ""
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group "
"requires a superuser admin."
msgstr ""
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the <code>auth."
"group_management</code> permission to allow a user to manage all groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
"groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr ""
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr ""
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr ""
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr ""
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr ""
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr ""
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr ""
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr ""
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr ""
@ -933,86 +971,86 @@ msgstr ""
msgid "Group Membership"
msgstr ""
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr ""
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to leave %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr ""
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr ""
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr ""
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr ""
@ -1074,16 +1112,6 @@ msgstr ""
msgid "Username"
msgstr ""
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr ""
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@ -1422,10 +1450,6 @@ msgstr ""
msgid "Code Name"
msgstr ""
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr ""
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr ""
@ -2146,11 +2170,11 @@ msgid ""
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
@ -2166,11 +2190,11 @@ msgid "AA Support Discord"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr ""
@ -2226,22 +2250,30 @@ msgid "Objective"
msgstr ""
#: allianceauth/timerboard/form.py:64
msgid "Days Remaining"
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Hours Remaining"
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:67
msgid "Minutes Remaining"
msgid "Hours Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr ""
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr ""

View File

@ -4,11 +4,11 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# frank1210 <francolopez_16@hotmail.com>, 2021
# Joel Falknau <ozirascal@gmail.com>, 2021
# Young Anexo, 2023
# Fegpawn Kaundur, 2023
# frank1210 <francolopez_16@hotmail.com>, 2023
# trenus, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
# Young Anexo, 2023
#
#, fuzzy
msgid ""
@ -16,8 +16,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: trenus, 2023\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: Young Anexo, 2023\n"
"Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View File

@ -4,14 +4,14 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# François LACROIX-DURANT <umbre@fallenstarscreations.com>, 2020
# Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2020
# Keven D. <theenarki@gmail.com>, 2020
# Idea ., 2021
# Mickael PATTE, 2021
# Geoffrey Fabbro, 2021
# Keven D. <theenarki@gmail.com>, 2023
# rockclodbuster, 2023
# Geoffrey Fabbro, 2023
# Mohssine Daghghar, 2023
# Ludovick Fortin, 2023
# François LACROIX-DURANT <umbre@fallenstarscreations.com>, 2023
# Mickael PATTE, 2023
# Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2023
# Idea ., 2023
#
#, fuzzy
msgid ""
@ -19,8 +19,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: Ludovick Fortin, 2023\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: Idea ., 2023\n"
"Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,9 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Foch Petain <brigadier.rockforward@gmail.com>, 2020
# Foch Petain <brigadier.rockforward@gmail.com>, 2023
# kotaneko, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
#
#, fuzzy
msgid ""
@ -13,8 +14,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: kotaneko, 2023\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2023\n"
"Language-Team: Japanese (https://app.transifex.com/alliance-auth/teams/107430/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View File

@ -4,13 +4,13 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# None None <khd1226543@gmail.com>, 2020
# Seowon Jung <seowon@hawaii.edu>, 2020
# Olgeda Choi <undead.choi@gmail.com>, 2020
# Lahty <js03js70@gmail.com>, 2020
# Joel Falknau <ozirascal@gmail.com>, 2020
# ThatRagingKid, 2022
# jackfrost, 2022
# None None <khd1226543@gmail.com>, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
# Seowon Jung <seowon@hawaii.edu>, 2023
# Olgeda Choi <undead.choi@gmail.com>, 2023
# ThatRagingKid, 2023
# Lahty <js03js70@gmail.com>, 2023
# jackfrost, 2023
#
#, fuzzy
msgid ""
@ -18,8 +18,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: jackfrost, 2022\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: jackfrost, 2023\n"
"Language-Team: Korean (Korea) (https://app.transifex.com/alliance-auth/teams/107430/ko_KR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View File

@ -4,9 +4,9 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Alexander Gess <de.alex.gess@gmail.com>, 2020
# Yuriy K <thedjcooltv@gmail.com>, 2020
# Андрей Зубков <and.vareba81@gmail.com>, 2020
# Yuriy K <thedjcooltv@gmail.com>, 2023
# Андрей Зубков <and.vareba81@gmail.com>, 2023
# Alexander Gess <de.alex.gess@gmail.com>, 2023
# Filipp Chertiev <f@fzfx.ru>, 2023
#
#, fuzzy
@ -15,7 +15,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: Filipp Chertiev <f@fzfx.ru>, 2023\n"
"Language-Team: Russian (https://app.transifex.com/alliance-auth/teams/107430/ru/)\n"
"MIME-Version: 1.0\n"

View File

@ -4,6 +4,7 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Denys Ivchenko, 2023
# Kristof Swensen, 2023
#
#, fuzzy
@ -12,7 +13,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: Kristof Swensen, 2023\n"
"Language-Team: Ukrainian (https://app.transifex.com/alliance-auth/teams/107430/uk/)\n"
"MIME-Version: 1.0\n"
@ -32,7 +33,7 @@ msgstr "Google Analytics V4"
#: allianceauth/authentication/decorators.py:37
msgid "A main character is required to perform that action. Add one below."
msgstr ""
"Для виконання цієї дії потрібен головний персонаж. Додайте його нижче."
"Для виконання цієї дії потрібен основний персонаж. Додайте його нижче."
#: allianceauth/authentication/forms.py:12
msgid "Email"
@ -124,7 +125,7 @@ msgstr "Додати персонажа"
#: allianceauth/authentication/templates/authentication/dashboard.html:115
msgid "Change Main"
msgstr "Змінити головного персонажа"
msgstr "Змінити основного персонажа"
#: allianceauth/authentication/templates/authentication/dashboard.html:125
msgid "Group Memberships"
@ -352,7 +353,7 @@ msgstr "Не вдалося зібрати статистику корпорац
#: allianceauth/fleetactivitytracking/auth_hooks.py:9
msgid "Fleet Activity Tracking"
msgstr "Відстеження активності флоту"
msgstr "Відстеження активності флотів"
#: allianceauth/fleetactivitytracking/forms.py:6 allianceauth/srp/form.py:8
#: allianceauth/srp/templates/srp/management.html:35
@ -456,7 +457,7 @@ msgstr "Корабель"
#: allianceauth/timerboard/templates/timerboard/view.html:202
#: allianceauth/timerboard/templates/timerboard/view.html:375
msgid "Eve Time"
msgstr "Час в грі"
msgstr "Ігровий час"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:33
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:36
@ -560,16 +561,16 @@ msgstr "Fats"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:4
msgid "Fatlink Corp Statistics"
msgstr "Статистика корпорації Fatlink"
msgstr "Статистика фатів корпорації"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:23
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:24
msgid "Average fats"
msgstr "Середній показник fats"
msgstr "Середній показник фатів"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:4
msgid "Fatlink statistics"
msgstr "Статистика Fatlink"
msgstr "Статистика фатів"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20
msgid "Ticker"
@ -625,7 +626,7 @@ msgid ""
"Cannot register the fleet participation for {character.character_name}. The "
"character needs to be online."
msgstr ""
"Не можна зареєструвати участь в флоті для {character.character_name}. "
"Не вдалося зареєструвати участь в флоті для {character.character_name}. "
"Персонаж повинен бути в мережі."
#: allianceauth/groupmanagement/auth_hooks.py:17
@ -659,8 +660,7 @@ msgstr ""
#: allianceauth/groupmanagement/models.py:113
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
"Група прихована від користувачів, але можна приєднатися з правильним "
"посиланням."
"Група прихована від користувачів, але можна приєднатися за посиланням."
#: allianceauth/groupmanagement/models.py:119
msgid ""
@ -1045,7 +1045,7 @@ msgstr "Ви вже є членом цієї групи."
#: allianceauth/groupmanagement/views.py:358
msgid "You already have a pending application for that group."
msgstr "У вас вже є очікуюча заявка на вступ до цієї групи."
msgstr "Ви вже подали заявку на вступ до цієї групи."
#: allianceauth/groupmanagement/views.py:367
#, python-format
@ -1062,7 +1062,7 @@ msgstr "Ви не є учасником цієї групи"
#: allianceauth/groupmanagement/views.py:393
msgid "You already have a pending leave request for that group."
msgstr "Ви вже маєте очікувану запит на вихід з цієї групи."
msgstr "Ви вже подали запит на вихід з цієї групи."
#: allianceauth/groupmanagement/views.py:409
#, python-format
@ -1321,7 +1321,7 @@ msgstr "Всі прочитані повідомлення видалено."
#: allianceauth/optimer/auth_hooks.py:10
msgid "Fleet Operations"
msgstr "Операції флоту"
msgstr "Флотові операції"
#: allianceauth/optimer/form.py:12
#: allianceauth/optimer/templates/optimer/fleetoptable.html:11
@ -1345,7 +1345,7 @@ msgstr "Тип операції"
#: allianceauth/optimer/form.py:17
#: allianceauth/srp/templates/srp/management.html:38
msgid "Fleet Commander"
msgstr "Командувач флоту"
msgstr "Командир флоту"
#: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14
#: allianceauth/srp/templates/srp/data.html:91
@ -1400,7 +1400,7 @@ msgstr "Немає наступних таймерів."
#: allianceauth/optimer/templates/optimer/management.html:33
msgid "Past Fleet Operations"
msgstr "Минулі флотові операції"
msgstr "Завершені флотові операції"
#: allianceauth/optimer/templates/optimer/management.html:37
#: allianceauth/timerboard/templates/timerboard/view.html:535
@ -1484,7 +1484,7 @@ msgstr "Стани"
#: allianceauth/services/abstract.py:72
msgid "That service account already exists"
msgstr "Такий обліковий запис сервісу вже існує"
msgstr "Такий сервісний обліковий запис вже існує"
#: allianceauth/services/abstract.py:103
#, python-brace-format
@ -1505,7 +1505,7 @@ msgstr "Командир флоту:"
#: allianceauth/services/forms.py:8
msgid "Fleet Comms:"
msgstr "Комунікації флоту:"
msgstr "Голосовий канал флоту:"
#: allianceauth/services/forms.py:9
msgid "Fleet Type:"
@ -1545,7 +1545,7 @@ msgstr "Ні"
#: allianceauth/services/forms.py:16
msgid "Important?*"
msgstr "Важливо?*"
msgstr "Важливий?*"
#: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31
msgid "Password"
@ -1614,7 +1614,7 @@ msgstr "Ви не маєте прав на доступ до Discourse."
#: allianceauth/services/modules/discourse/views.py:34
msgid "You must have a main character set to access Discourse."
msgstr "Ви повинні мати головний персонаж, щоб отримати доступ до Discourse."
msgstr "Ви повинні мати основний персонаж, щоб отримати доступ до Discourse."
#: allianceauth/services/modules/discourse/views.py:44
msgid ""
@ -1702,7 +1702,7 @@ msgstr "Відправлено трансляцію Jabber на %s"
#: allianceauth/services/modules/openfire/views.py:144
msgid "Set jabber password."
msgstr "Встановлення пароля Jabber."
msgstr "Встановити пароль Jabber."
#: allianceauth/services/modules/phpbb3/views.py:34
msgid "Activated forum account."
@ -1713,7 +1713,7 @@ msgstr "Активований обліковий запис форуму."
#: allianceauth/services/modules/phpbb3/views.py:78
#: allianceauth/services/modules/phpbb3/views.py:101
msgid "An error occurred while processing your forum account."
msgstr "Виникла помилка під час обробки вашого облікового запису форуму."
msgstr "Виникла помилка під час обробки вашого облікового запису на форумі."
#: allianceauth/services/modules/phpbb3/views.py:53
msgid "Deactivated forum account."
@ -1721,11 +1721,11 @@ msgstr "Деактивований обліковий запис форуму."
#: allianceauth/services/modules/phpbb3/views.py:70
msgid "Reset forum password."
msgstr "Скидання пароля форуму."
msgstr "Скинути пароль форуму."
#: allianceauth/services/modules/phpbb3/views.py:98
msgid "Set forum password."
msgstr "Встановлення пароля форуму."
msgstr "Встановити пароль форуму."
#: allianceauth/services/modules/smf/views.py:52
msgid "Activated SMF account."
@ -1744,11 +1744,11 @@ msgstr "Деактивований обліковий запис SMF."
#: allianceauth/services/modules/smf/views.py:95
msgid "Reset SMF password."
msgstr "Скидання пароля SMF."
msgstr "Скинути пароль SMF."
#: allianceauth/services/modules/smf/views.py:121
msgid "Set SMF password."
msgstr "Встановлення пароля SMF."
msgstr "Встановити пароль SMF."
#: allianceauth/services/modules/teamspeak3/forms.py:14
#, python-format
@ -1761,7 +1761,7 @@ msgstr "Оновити групи TS3"
#: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:5
msgid "Verify Teamspeak"
msgstr "Перевірте Teamspeak"
msgstr "Перевірити Teamspeak"
#: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:10
msgid "Verify Teamspeak Identity"
@ -1869,11 +1869,11 @@ msgstr "Керування послугами"
#: allianceauth/services/templates/services/services.html:9
msgid "Available Services"
msgstr "Доступні послуги"
msgstr "Доступні сервіси"
#: allianceauth/services/templates/services/services.html:14
msgid "Service"
msgstr "Послуга"
msgstr "Сервіс"
#: allianceauth/services/templates/services/services.html:16
msgid "Domain"
@ -1881,7 +1881,7 @@ msgstr "Домен"
#: allianceauth/srp/auth_hooks.py:13
msgid "Ship Replacement"
msgstr "Компенсація за корабель"
msgstr "Компенсації"
#: allianceauth/srp/form.py:9
#: allianceauth/srp/templates/srp/management.html:36

View File

@ -4,9 +4,10 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Joel Falknau <ozirascal@gmail.com>, 2020
# Jesse . <sgeine@hotmail.com>, 2020
# Aaron BuBu <351793078@qq.com>, 2020
# Jesse . <sgeine@hotmail.com>, 2023
# Aaron BuBu <351793078@qq.com>, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
# Shen Yang, 2023
#
#, fuzzy
msgid ""
@ -14,8 +15,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: Aaron BuBu <351793078@qq.com>, 2020\n"
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
"Last-Translator: Shen Yang, 2023\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/alliance-auth/teams/107430/zh-Hans/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -46,48 +47,48 @@ msgstr ""
#: allianceauth/authentication/models.py:80
msgid "English"
msgstr ""
msgstr "英语"
#: allianceauth/authentication/models.py:81
msgid "German"
msgstr ""
msgstr "德语"
#: allianceauth/authentication/models.py:82
msgid "Spanish"
msgstr ""
msgstr "西班牙语"
#: allianceauth/authentication/models.py:83
msgid "Chinese Simplified"
msgstr ""
msgstr "简体中文"
#: allianceauth/authentication/models.py:84
msgid "Russian"
msgstr ""
msgstr "俄语"
#: allianceauth/authentication/models.py:85
msgid "Korean"
msgstr ""
msgstr "韩语"
#: allianceauth/authentication/models.py:86
msgid "French"
msgstr ""
msgstr "法语"
#: allianceauth/authentication/models.py:87
msgid "Japanese"
msgstr ""
msgstr "日语"
#: allianceauth/authentication/models.py:88
msgid "Italian"
msgstr ""
msgstr "意大利语"
#: allianceauth/authentication/models.py:91
msgid "Language"
msgstr ""
msgstr "语言"
#: allianceauth/authentication/models.py:96
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr ""
msgstr "夜间模式"
#: allianceauth/authentication/models.py:110
#, python-format
@ -696,7 +697,7 @@ msgstr ""
#: allianceauth/groupmanagement/models.py:215
msgid "reason"
msgstr ""
msgstr "原因"
#: allianceauth/groupmanagement/models.py:215
msgid "Reason why this name is reserved."
@ -754,7 +755,7 @@ msgstr "操作者"
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:48
msgid "Removed"
msgstr ""
msgstr "已移除"
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:60
msgid "All times displayed are EVE/UTC."
@ -1198,11 +1199,11 @@ msgstr "添加评论"
#: allianceauth/notifications/models.py:21
msgid "danger"
msgstr ""
msgstr "危险"
#: allianceauth/notifications/models.py:22
msgid "warning"
msgstr ""
msgstr "警告"
#: allianceauth/notifications/models.py:23
msgid "info"
@ -1343,7 +1344,7 @@ msgstr "当前EVE游戏内时间"
#: allianceauth/optimer/templates/optimer/management.html:26
msgid "Next Fleet Operations"
msgstr ""
msgstr "下一个舰队任务"
#: allianceauth/optimer/templates/optimer/management.html:30
#: allianceauth/timerboard/templates/timerboard/view.html:362
@ -1352,7 +1353,7 @@ msgstr "没有快到的时间节点,歇一会吧"
#: allianceauth/optimer/templates/optimer/management.html:33
msgid "Past Fleet Operations"
msgstr ""
msgstr "过去的舰队任务"
#: allianceauth/optimer/templates/optimer/management.html:37
#: allianceauth/timerboard/templates/timerboard/view.html:535
@ -2257,15 +2258,15 @@ msgstr ""
#: allianceauth/timerboard/models.py:15
msgid "Shield"
msgstr ""
msgstr "护盾"
#: allianceauth/timerboard/models.py:16
msgid "Armor"
msgstr ""
msgstr "装甲"
#: allianceauth/timerboard/models.py:17
msgid "Hull"
msgstr ""
msgstr "结构"
#: allianceauth/timerboard/models.py:18
msgid "Final"
@ -2273,11 +2274,11 @@ msgstr ""
#: allianceauth/timerboard/models.py:19
msgid "Anchoring"
msgstr ""
msgstr "铆钉"
#: allianceauth/timerboard/models.py:20
msgid "Unanchoring"
msgstr ""
msgstr "解锚"
#: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:11
msgid "Delete Timer"

View File

@ -11,6 +11,9 @@ from .models import DiscordUser
from .urls import urlpatterns
from .utils import LoggerAddTag
from . import tasks, __title__
from .app_settings import (
DISCORD_SYNC_NAMES
)
logger = LoggerAddTag(logging.getLogger(__name__), __title__)
@ -99,17 +102,18 @@ class DiscordService(ServicesHook):
return has_perms
def sync_nickname(self, user):
logger.debug('Syncing %s nickname for user %s', self.name, user)
if self.user_has_account(user):
tasks.update_nickname.apply_async(
kwargs={
'user_pk': user.pk,
# since the new nickname is not yet in the DB we need to
# provide it manually to the task
'nickname': user_formatted_nick(user)
},
priority=SINGLE_TASK_PRIORITY
)
if DISCORD_SYNC_NAMES:
logger.debug('Syncing %s nickname for user %s', self.name, user)
if self.user_has_account(user):
tasks.update_nickname.apply_async(
kwargs={
'user_pk': user.pk,
# since the new nickname is not yet in the DB we need to
# provide it manually to the task
'nickname': user_formatted_nick(user)
},
priority=SINGLE_TASK_PRIORITY
)
def sync_nicknames_bulk(self, users: list):
"""Sync nickname for a list of users in bulk.

View File

@ -81,11 +81,18 @@ class TestDiscordService(NoSocketsTestCase):
self.assertFalse(DiscordUser.objects.filter(user=self.none_member).exists())
@patch(MODULE_PATH + '.tasks.update_nickname')
@patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True)
def test_sync_nickname(self, mock_update_nickname):
service = self.service()
service.sync_nickname(self.member)
self.assertTrue(mock_update_nickname.apply_async.called)
@patch(MODULE_PATH + '.tasks.update_nickname')
def test_sync_nickname_no_setting(self, mock_update_nickname):
service = self.service()
service.sync_nickname(self.member)
self.assertFalse(mock_update_nickname.apply_async.called)
@patch(MODULE_PATH + '.tasks.update_nicknames_bulk')
def test_sync_nicknames_bulk(self, mock_update_nicknames_bulk):
service = self.service()

View File

@ -164,6 +164,7 @@ class TestServiceFeatures(TransactionTestCase):
self.discord_user = DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
@patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True)
def test_when_name_of_main_changes_then_discord_nick_is_updated(
self, requests_mocker
):
@ -185,6 +186,7 @@ class TestServiceFeatures(TransactionTestCase):
self.assertTrue(nick_updated)
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
@patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True)
def test_when_name_of_main_changes_and_user_deleted_then_account_is_deleted(
self, requests_mocker
):

View File

@ -1,7 +1,7 @@
PROTOCOL=https://
AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN%
DOMAIN=%DOMAIN%
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v3.7.1
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v3.8.0
# Nginx Proxy Manager
PROXY_HTTP_PORT=80

View File

@ -1,5 +1,5 @@
FROM python:3.9-slim
ARG AUTH_VERSION=v3.7.1
ARG AUTH_VERSION=v3.8.0
ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION}
ENV VIRTUAL_ENV=/opt/venv
ENV AUTH_USER=allianceauth

View File

@ -9,7 +9,9 @@ Tuning usually has benefits and costs and should only be performed by experience
:::{toctree}
:maxdepth: 1
gunicorn
celery
redis
:::
gunicorn
celery
redis
python
sql
```

View File

@ -0,0 +1,633 @@
# Python
## Version Update
Newer versions of python can focus heavily on performance improvements, some more than others. But be aware regressions for stability or security reasons may always be the case.
As a general rule, Python 3.9 and Python 3.11 both had a strong focus on performance improvements. Python 3.12 is looking promising but has yet to have widespread testing, adoption and deployment. A simple comparison is available at [speed.python.org](https://speed.python.org/comparison/?exe=12%2BL%2B3.11%2C12%2BL%2B3.12%2C12%2BL%2B3.10%2C12%2BL%2B3.9%2C12%2BL%2B3.8&ben=746&env=1&hor=false&bas=none&chart=normal+bars).
[Djangobench](https://github.com/django/djangobench/tree/master) is source of synthetic benchmarks and a useful tool for running comparisons. Below are some examples to inform your investigations.
Keep in mind while a 1.2x faster result is significant, it's only one step of the process, Celery, SQL, Redis and many other factors will influence the end result and this _python_ speed improvement will not translate 1:1 into real world performance.
### Django 4.0.10
- Djangobench 0.10.0
- Django 4.0.10
- Python 3.8.18 vs Python 3.11.5
```bash
joel@METABOX:~/djangobench/django$ djangobench --vcs=none --control=. --experiment=. --control-python=/home/joel/djangobench/py38/bin/python --experiment-python=/home/joel/djangobench/py311/bin/python -r /home/joel/djangobench/results -t 500
Running all benchmarks
Recording data to '/home/joel/djangobench/results'
Control: Django 4.0.10 (in .)
Experiment: Django 4.0.10 (in .)
Running 'multi_value_dict' benchmark ...
Min: 0.000014 -> 0.000013: 1.0304x faster
Avg: 0.000183 -> 0.000133: 1.3698x faster
Significant (t=9.325958)
Stddev: 0.00010 -> 0.00007: 1.3791x smaller (N = 500)
Running 'query_values' benchmark ...
Min: 0.000079 -> 0.000070: 1.1308x faster
Avg: 0.000084 -> 0.000074: 1.1267x faster
Significant (t=19.174361)
Stddev: 0.00001 -> 0.00001: 1.0255x larger (N = 500)
Running 'query_delete' benchmark ...
Min: 0.000082 -> 0.000074: 1.1145x faster
Avg: 0.000086 -> 0.000078: 1.0987x faster
Significant (t=17.504085)
Stddev: 0.00001 -> 0.00001: 1.1888x smaller (N = 500)
Running 'query_select_related' benchmark ...
Min: 0.016771 -> 0.013520: 1.2405x faster
Avg: 0.017897 -> 0.014149: 1.2649x faster
Significant (t=40.942990)
Stddev: 0.00190 -> 0.00077: 2.4535x smaller (N = 500)
Running 'query_aggregate' benchmark ...
Min: 0.000092 -> 0.000083: 1.1105x faster
Avg: 0.000100 -> 0.000090: 1.1107x faster
Significant (t=9.967204)
Stddev: 0.00002 -> 0.00001: 1.5003x smaller (N = 500)
Running 'query_raw_deferred' benchmark ...
Min: 0.004157 -> 0.003563: 1.1666x faster
Avg: 0.004626 -> 0.003809: 1.2143x faster
Significant (t=12.325104)
Stddev: 0.00121 -> 0.00086: 1.4047x smaller (N = 500)
Running 'query_get_or_create' benchmark ...
Min: 0.000412 -> 0.000362: 1.1385x faster
Avg: 0.000458 -> 0.000407: 1.1259x faster
Significant (t=14.169322)
Stddev: 0.00006 -> 0.00005: 1.1306x smaller (N = 500)
Running 'query_values_list' benchmark ...
Min: 0.000080 -> 0.000071: 1.1231x faster
Avg: 0.000089 -> 0.000076: 1.1706x faster
Significant (t=18.298942)
Stddev: 0.00001 -> 0.00001: 1.9398x smaller (N = 500)
Running 'url_resolve_flat_i18n_off' benchmark ...
Min: 0.055764 -> 0.045370: 1.2291x faster
Avg: 0.057670 -> 0.047020: 1.2265x faster
Significant (t=111.187780)
Stddev: 0.00206 -> 0.00059: 3.4618x smaller (N = 500)
Running 'qs_filter_chaining' benchmark ...
Min: 0.000236 -> 0.000196: 1.2034x faster
Avg: 0.000248 -> 0.000206: 1.2041x faster
Significant (t=44.893544)
Stddev: 0.00002 -> 0.00001: 1.0833x smaller (N = 500)
Running 'template_render' benchmark ...
Min: 0.000933 -> 0.000712: 1.3110x faster
Avg: 0.001003 -> 0.000777: 1.2909x faster
Significant (t=8.379095)
Stddev: 0.00043 -> 0.00042: 1.0287x smaller (N = 500)
Running 'query_get' benchmark ...
Min: 0.000259 -> 0.000230: 1.1259x faster
Avg: 0.000282 -> 0.000238: 1.1829x faster
Significant (t=42.267305)
Stddev: 0.00002 -> 0.00001: 1.7842x smaller (N = 500)
Running 'query_none' benchmark ...
Min: 0.000053 -> 0.000045: 1.1830x faster
Avg: 0.000056 -> 0.000049: 1.1449x faster
Significant (t=16.426843)
Stddev: 0.00001 -> 0.00001: 1.1267x larger (N = 500)
Running 'query_complex_filter' benchmark ...
Min: 0.000039 -> 0.000034: 1.1527x faster
Avg: 0.000041 -> 0.000037: 1.1091x faster
Significant (t=13.582718)
Stddev: 0.00000 -> 0.00001: 1.5373x larger (N = 500)
Running 'query_filter' benchmark ...
Min: 0.000127 -> 0.000112: 1.1288x faster
Avg: 0.000133 -> 0.000119: 1.1228x faster
Significant (t=22.727829)
Stddev: 0.00001 -> 0.00001: 1.1771x smaller (N = 500)
Running 'template_render_simple' benchmark ...
Min: 0.000030 -> 0.000024: 1.2405x faster
Avg: 0.000035 -> 0.000029: 1.2042x faster
Not significant
Stddev: 0.00007 -> 0.00005: 1.3190x smaller (N = 500)
Running 'default_middleware' benchmark ...
Min: -0.000047 -> -0.000054: 0.8624x faster
Avg: 0.000017 -> 0.000017: 1.0032x faster
Not significant
Stddev: 0.00037 -> 0.00037: 1.0091x larger (N = 500)
Running 'query_annotate' benchmark ...
Min: 0.000186 -> 0.000162: 1.1505x faster
Avg: 0.000207 -> 0.000178: 1.1660x faster
Significant (t=16.516089)
Stddev: 0.00003 -> 0.00003: 1.1403x smaller (N = 500)
Running 'raw_sql' benchmark ...
Min: 0.000015 -> 0.000013: 1.1070x faster
Avg: 0.000017 -> 0.000014: 1.1676x faster
Significant (t=13.598519)
Stddev: 0.00000 -> 0.00000: 2.3503x smaller (N = 500)
Running 'url_resolve_flat' benchmark ...
Min: 0.056378 -> 0.044772: 1.2592x faster
Avg: 0.058268 -> 0.046656: 1.2489x faster
Significant (t=197.176590)
Stddev: 0.00121 -> 0.00051: 2.3665x smaller (N = 500)
Running 'l10n_render' benchmark ...
Min: 0.001097 -> 0.000727: 1.5092x faster
Avg: 0.001160 -> 0.000768: 1.5101x faster
Significant (t=36.971179)
Stddev: 0.00019 -> 0.00014: 1.2946x smaller (N = 500)
Running 'query_count' benchmark ...
Min: 0.000083 -> 0.000073: 1.1302x faster
Avg: 0.000091 -> 0.000079: 1.1640x faster
Significant (t=15.049336)
Stddev: 0.00002 -> 0.00001: 1.6661x smaller (N = 500)
Running 'model_delete' benchmark ...
Min: 0.000123 -> 0.000105: 1.1701x faster
Avg: 0.000135 -> 0.000119: 1.1396x faster
Significant (t=17.781816)
Stddev: 0.00001 -> 0.00002: 1.1990x larger (N = 500)
Running 'query_iterator' benchmark ...
Min: 0.000102 -> 0.000088: 1.1605x faster
Avg: 0.000108 -> 0.000093: 1.1598x faster
Significant (t=23.872009)
Stddev: 0.00001 -> 0.00001: 1.1366x smaller (N = 500)
Running 'template_compilation' benchmark ...
Min: 0.000155 -> 0.000129: 1.2015x faster
Avg: 0.000169 -> 0.000137: 1.2317x faster
Significant (t=6.119618)
Stddev: 0.00009 -> 0.00007: 1.4162x smaller (N = 500)
Running 'query_all_multifield' benchmark ...
Min: 0.014582 -> 0.012509: 1.1658x faster
Avg: 0.015715 -> 0.013337: 1.1783x faster
Significant (t=19.183517)
Stddev: 0.00207 -> 0.00184: 1.1241x smaller (N = 500)
Running 'query_prefetch_related' benchmark ...
Min: 0.014293 -> 0.012157: 1.1758x faster
Avg: 0.015467 -> 0.013276: 1.1650x faster
Significant (t=20.607411)
Stddev: 0.00176 -> 0.00160: 1.0952x smaller (N = 500)
Running 'query_all_converters' benchmark ...
Min: 0.000536 -> 0.000464: 1.1554x faster
Avg: 0.000563 -> 0.000486: 1.1595x faster
Significant (t=38.503433)
Stddev: 0.00004 -> 0.00002: 1.6468x smaller (N = 500)
Running 'query_distinct' benchmark ...
Min: 0.000106 -> 0.000092: 1.1583x faster
Avg: 0.000127 -> 0.000096: 1.3223x faster
Significant (t=27.798102)
Stddev: 0.00002 -> 0.00001: 3.7187x smaller (N = 500)
Running 'query_dates' benchmark ...
Min: 0.000249 -> 0.000209: 1.1953x faster
Avg: 0.000275 -> 0.000228: 1.2056x faster
Significant (t=30.785168)
Stddev: 0.00003 -> 0.00002: 1.0854x smaller (N = 500)
Running 'model_save_existing' benchmark ...
Min: 0.003526 -> 0.003094: 1.1397x faster
Avg: 0.003723 -> 0.003212: 1.1591x faster
Significant (t=47.274918)
Stddev: 0.00018 -> 0.00016: 1.1817x smaller (N = 500)
Running 'query_delete_related' benchmark ...
Min: 0.000120 -> 0.000103: 1.1655x faster
Avg: 0.000132 -> 0.000111: 1.1815x faster
Significant (t=6.428771)
Stddev: 0.00005 -> 0.00004: 1.2149x smaller (N = 500)
Running 'url_reverse' benchmark ...
Min: 0.000062 -> 0.000060: 1.0318x faster
Avg: 0.000072 -> 0.000068: 1.0622x faster
Not significant
Stddev: 0.00006 -> 0.00005: 1.0531x smaller (N = 500)
Running 'query_latest' benchmark ...
Min: 0.000136 -> 0.000118: 1.1454x faster
Avg: 0.000155 -> 0.000129: 1.2008x faster
Significant (t=8.372115)
Stddev: 0.00007 -> 0.00001: 5.1365x smaller (N = 500)
Running 'form_create' benchmark ...
Min: 0.000015 -> 0.000013: 1.2319x faster
Avg: 0.000019 -> 0.000015: 1.2739x faster
Significant (t=4.158080)
Stddev: 0.00002 -> 0.00001: 1.1449x smaller (N = 500)
Running 'query_update' benchmark ...
Min: 0.000047 -> 0.000041: 1.1323x faster
Avg: 0.000052 -> 0.000044: 1.1721x faster
Significant (t=18.470635)
Stddev: 0.00001 -> 0.00000: 1.6104x smaller (N = 500)
Running 'query_in_bulk' benchmark ...
Min: 0.000152 -> 0.000136: 1.1193x faster
Avg: 0.000173 -> 0.000147: 1.1735x faster
Significant (t=16.901845)
Stddev: 0.00003 -> 0.00001: 2.1199x smaller (N = 500)
Running 'url_resolve_nested' benchmark ...
Min: 0.000043 -> 0.000034: 1.2871x faster
Avg: 0.000075 -> 0.000047: 1.6049x faster
Not significant
Stddev: 0.00066 -> 0.00023: 2.8387x smaller (N = 500)
Running 'model_creation' benchmark ...
Min: 0.000077 -> 0.000066: 1.1579x faster
Avg: 0.000088 -> 0.000072: 1.2205x faster
Significant (t=10.514202)
Stddev: 0.00003 -> 0.00001: 3.1410x smaller (N = 500)
Running 'query_order_by' benchmark ...
Min: 0.000135 -> 0.000124: 1.0945x faster
Avg: 0.000145 -> 0.000133: 1.0902x faster
Significant (t=13.574502)
Stddev: 0.00001 -> 0.00001: 1.1586x smaller (N = 500)
Running 'startup' benchmark ...
Skipped: Django 1.9 and later has changed app loading. This benchmark needs fixing anyway.
Running 'form_clean' benchmark ...
Min: 0.000005 -> 0.000003: 1.4696x faster
Avg: 0.000006 -> 0.000004: 1.4931x faster
Significant (t=11.263253)
Stddev: 0.00000 -> 0.00000: 2.2571x smaller (N = 500)
Running 'locale_from_request' benchmark ...
Min: 0.000076 -> 0.000082: 1.0895x slower
Avg: 0.000083 -> 0.000090: 1.0877x slower
Not significant
Stddev: 0.00009 -> 0.00006: 1.6230x smaller (N = 500)
Running 'query_exists' benchmark ...
Min: 0.000243 -> 0.000214: 1.1399x faster
Avg: 0.000262 -> 0.000227: 1.1571x faster
Significant (t=27.797738)
Stddev: 0.00002 -> 0.00002: 1.2601x smaller (N = 500)
Running 'query_values_10000' benchmark ...
Min: 0.005755 -> 0.005269: 1.0923x faster
Avg: 0.006184 -> 0.005587: 1.1067x faster
Significant (t=10.895954)
Stddev: 0.00094 -> 0.00079: 1.1902x smaller (N = 500)
Running 'query_exclude' benchmark ...
Min: 0.000159 -> 0.000141: 1.1256x faster
Avg: 0.000177 -> 0.000151: 1.1741x faster
Significant (t=23.556200)
Stddev: 0.00002 -> 0.00001: 1.8250x smaller (N = 500)
Running 'query_raw' benchmark ...
Min: 0.005619 -> 0.004860: 1.1562x faster
Avg: 0.006181 -> 0.005041: 1.2263x faster
Significant (t=18.008590)
Stddev: 0.00121 -> 0.00074: 1.6376x smaller (N = 500)
Running 'url_resolve' benchmark ...
Min: 0.004666 -> 0.004233: 1.1023x faster
Avg: 0.004920 -> 0.004347: 1.1318x faster
Significant (t=24.865249)
Stddev: 0.00049 -> 0.00016: 3.1507x smaller (N = 500)
Running 'model_save_new' benchmark ...
Min: 0.003420 -> 0.003105: 1.1014x faster
Avg: 0.003610 -> 0.003217: 1.1221x faster
Significant (t=42.956103)
Stddev: 0.00017 -> 0.00011: 1.6304x smaller (N = 500)
Running 'query_all' benchmark ...
Min: 0.008101 -> 0.007077: 1.1447x faster
Avg: 0.009006 -> 0.007936: 1.1348x faster
Significant (t=9.981534)
Stddev: 0.00171 -> 0.00168: 1.0215x smaller (N = 500)
```
### Django 4.2.6
- Djangobench 0.10.0
- Django 4.0.10
- Python 3.8.18 vs Python 3.11.5
```bash
joel@METABOX:~/djangobench/django$ djangobench --vcs=none --control=. --experiment=. --control-python=/home/joel/djangobench/py38/bin/python --experiment-python=/home/joel/djangobench/py311/bin/python -r /home/joel/djangobench/results -t 500
Running all benchmarks
Recording data to '/home/joel/djangobench/results'
Control: Django 4.2.6 (in .)
Experiment: Django 4.2.6 (in .)
Running 'multi_value_dict' benchmark ...
Min: -0.000004 -> 0.000013: -3.0336x slower
Avg: 0.000182 -> 0.000133: 1.3680x faster
Significant (t=9.151616)
Stddev: 0.00010 -> 0.00007: 1.3826x smaller (N = 500)
Running 'query_values' benchmark ...
Min: 0.000082 -> 0.000072: 1.1485x faster
Avg: 0.000086 -> 0.000075: 1.1462x faster
Significant (t=30.114973)
Stddev: 0.00001 -> 0.00001: 1.0258x larger (N = 500)
Running 'query_delete' benchmark ...
Min: 0.000080 -> 0.000071: 1.1169x faster
Avg: 0.000086 -> 0.000077: 1.1088x faster
Significant (t=13.459411)
Stddev: 0.00001 -> 0.00001: 1.0008x smaller (N = 500)
Running 'query_select_related' benchmark ...
Min: 0.016889 -> 0.013513: 1.2498x faster
Avg: 0.018370 -> 0.013885: 1.3230x faster
Significant (t=48.921967)
Stddev: 0.00196 -> 0.00061: 3.2174x smaller (N = 500)
Running 'query_aggregate' benchmark ...
Min: 0.000167 -> 0.000153: 1.0904x faster
Avg: 0.000182 -> 0.000165: 1.1029x faster
Significant (t=12.685517)
Stddev: 0.00002 -> 0.00002: 1.3019x smaller (N = 500)
Running 'query_raw_deferred' benchmark ...
Min: 0.004160 -> 0.003674: 1.1323x faster
Avg: 0.004596 -> 0.003888: 1.1820x faster
Significant (t=11.504156)
Stddev: 0.00117 -> 0.00073: 1.5957x smaller (N = 500)
Running 'query_get_or_create' benchmark ...
Min: 0.000421 -> 0.000356: 1.1823x faster
Avg: 0.000470 -> 0.000392: 1.2011x faster
Significant (t=14.613017)
Stddev: 0.00008 -> 0.00009: 1.0954x larger (N = 500)
Running 'query_values_list' benchmark ...
Min: 0.000080 -> 0.000070: 1.1395x faster
Avg: 0.000085 -> 0.000075: 1.1202x faster
Significant (t=20.300988)
Stddev: 0.00001 -> 0.00001: 1.0537x smaller (N = 500)
Running 'url_resolve_flat_i18n_off' benchmark ...
Min: 0.056031 -> 0.045854: 1.2219x faster
Avg: 0.057048 -> 0.048370: 1.1794x faster
Significant (t=106.668460)
Stddev: 0.00117 -> 0.00139: 1.1819x larger (N = 500)
Running 'qs_filter_chaining' benchmark ...
Min: 0.000247 -> 0.000205: 1.2080x faster
Avg: 0.000267 -> 0.000219: 1.2211x faster
Significant (t=38.507950)
Stddev: 0.00002 -> 0.00002: 1.0252x larger (N = 500)
Running 'template_render' benchmark ...
Min: 0.000956 -> 0.000761: 1.2550x faster
Avg: 0.001061 -> 0.000862: 1.2302x faster
Significant (t=6.128572)
Stddev: 0.00052 -> 0.00051: 1.0109x smaller (N = 500)
Running 'query_get' benchmark ...
Min: 0.000268 -> 0.000235: 1.1388x faster
Avg: 0.000293 -> 0.000256: 1.1411x faster
Significant (t=24.002331)
Stddev: 0.00002 -> 0.00003: 1.2917x larger (N = 500)
Running 'query_none' benchmark ...
Min: 0.000055 -> 0.000050: 1.1079x faster
Avg: 0.000061 -> 0.000055: 1.1183x faster
Significant (t=3.149707)
Stddev: 0.00003 -> 0.00004: 1.3162x larger (N = 500)
Running 'query_complex_filter' benchmark ...
Min: 0.000040 -> 0.000034: 1.1777x faster
Avg: 0.000042 -> 0.000038: 1.1267x faster
Significant (t=15.246074)
Stddev: 0.00000 -> 0.00001: 1.5250x larger (N = 500)
Running 'query_filter' benchmark ...
Min: 0.000131 -> 0.000116: 1.1288x faster
Avg: 0.000139 -> 0.000127: 1.0907x faster
Significant (t=14.448319)
Stddev: 0.00001 -> 0.00001: 1.2281x larger (N = 500)
Running 'template_render_simple' benchmark ...
Min: 0.000031 -> 0.000024: 1.2650x faster
Avg: 0.000037 -> 0.000029: 1.2895x faster
Significant (t=2.094800)
Stddev: 0.00007 -> 0.00005: 1.3630x smaller (N = 500)
Running 'default_middleware' benchmark ...
Min: -0.000037 -> -0.000060: 0.6180x faster
Avg: 0.000001 -> 0.000001: 1.0056x slower
Not significant
Stddev: 0.00002 -> 0.00002: 1.0915x smaller (N = 500)
Running 'query_annotate' benchmark ...
Min: 0.000192 -> 0.000173: 1.1122x faster
Avg: 0.000206 -> 0.000185: 1.1134x faster
Significant (t=17.849733)
Stddev: 0.00002 -> 0.00002: 1.0456x smaller (N = 500)
Running 'raw_sql' benchmark ...
Min: 0.000013 -> 0.000012: 1.0839x faster
Avg: 0.000015 -> 0.000014: 1.0882x faster
Significant (t=4.252084)
Stddev: 0.00001 -> 0.00000: 1.5868x smaller (N = 500)
Running 'url_resolve_flat' benchmark ...
Min: 0.055540 -> 0.046018: 1.2069x faster
Avg: 0.058030 -> 0.048408: 1.1988x faster
Significant (t=98.852976)
Stddev: 0.00157 -> 0.00151: 1.0444x smaller (N = 500)
Running 'l10n_render' benchmark ...
Min: 0.001604 -> 0.001253: 1.2797x faster
Avg: 0.001684 -> 0.001304: 1.2918x faster
Significant (t=37.535402)
Stddev: 0.00017 -> 0.00015: 1.1476x smaller (N = 500)
Running 'query_count' benchmark ...
Min: 0.000176 -> 0.000165: 1.0631x faster
Avg: 0.000189 -> 0.000176: 1.0755x faster
Significant (t=12.229046)
Stddev: 0.00002 -> 0.00002: 1.0395x larger (N = 500)
Running 'model_delete' benchmark ...
Min: 0.000122 -> 0.000104: 1.1743x faster
Avg: 0.000152 -> 0.000115: 1.3227x faster
Significant (t=19.812953)
Stddev: 0.00004 -> 0.00001: 2.6554x smaller (N = 500)
Running 'query_iterator' benchmark ...
Min: 0.000108 -> 0.000094: 1.1518x faster
Avg: 0.000119 -> 0.000098: 1.2203x faster
Significant (t=21.984884)
Stddev: 0.00002 -> 0.00001: 2.7750x smaller (N = 500)
Running 'template_compilation' benchmark ...
Min: 0.000164 -> 0.000148: 1.1034x faster
Avg: 0.000184 -> 0.000162: 1.1386x faster
Significant (t=4.665298)
Stddev: 0.00008 -> 0.00007: 1.2952x smaller (N = 500)
Running 'query_all_multifield' benchmark ...
Min: 0.014802 -> 0.012188: 1.2144x faster
Avg: 0.016029 -> 0.013294: 1.2057x faster
Significant (t=21.516971)
Stddev: 0.00210 -> 0.00191: 1.0984x smaller (N = 500)
Running 'query_prefetch_related' benchmark ...
Min: 0.013401 -> 0.011583: 1.1569x faster
Avg: 0.014822 -> 0.013366: 1.1090x faster
Significant (t=11.422100)
Stddev: 0.00170 -> 0.00229: 1.3410x larger (N = 500)
Running 'query_all_converters' benchmark ...
Min: 0.000499 -> 0.000429: 1.1618x faster
Avg: 0.000531 -> 0.000455: 1.1670x faster
Significant (t=42.716720)
Stddev: 0.00002 -> 0.00003: 1.5394x larger (N = 500)
Running 'query_distinct' benchmark ...
Min: 0.000108 -> 0.000095: 1.1397x faster
Avg: 0.000116 -> 0.000100: 1.1646x faster
Significant (t=25.915629)
Stddev: 0.00001 -> 0.00001: 1.1204x larger (N = 500)
Running 'query_dates' benchmark ...
Min: 0.000333 -> 0.000290: 1.1490x faster
Avg: 0.000365 -> 0.000326: 1.1207x faster
Significant (t=18.213858)
Stddev: 0.00003 -> 0.00003: 1.0118x larger (N = 500)
Running 'model_save_existing' benchmark ...
Min: 0.003455 -> 0.003081: 1.1215x faster
Avg: 0.003764 -> 0.003326: 1.1316x faster
Significant (t=32.229651)
Stddev: 0.00023 -> 0.00020: 1.1398x smaller (N = 500)
Running 'query_delete_related' benchmark ...
Min: 0.000122 -> 0.000102: 1.1946x faster
Avg: 0.000131 -> 0.000113: 1.1564x faster
Significant (t=5.027485)
Stddev: 0.00005 -> 0.00006: 1.4129x larger (N = 500)
Running 'url_reverse' benchmark ...
Min: 0.000068 -> 0.000067: 1.0193x faster
Avg: 0.000075 -> 0.000074: 1.0157x faster
Not significant
Stddev: 0.00006 -> 0.00005: 1.1543x smaller (N = 500)
Running 'query_latest' benchmark ...
Min: 0.000147 -> 0.000138: 1.0631x faster
Avg: 0.000167 -> 0.000148: 1.1277x faster
Significant (t=11.353029)
Stddev: 0.00003 -> 0.00002: 1.6091x smaller (N = 500)
Running 'form_create' benchmark ...
Min: 0.000016 -> 0.000013: 1.2659x faster
Avg: 0.000020 -> 0.000015: 1.2770x faster
Significant (t=3.482649)
Stddev: 0.00002 -> 0.00002: 1.0947x larger (N = 500)
Running 'query_update' benchmark ...
Min: 0.000047 -> 0.000043: 1.0971x faster
Avg: 0.000050 -> 0.000046: 1.0691x faster
Significant (t=9.363513)
Stddev: 0.00001 -> 0.00000: 1.2636x smaller (N = 500)
Running 'query_in_bulk' benchmark ...
Min: 0.000157 -> 0.000143: 1.0970x faster
Avg: 0.000178 -> 0.000162: 1.0981x faster
Significant (t=9.031182)
Stddev: 0.00002 -> 0.00003: 1.5173x larger (N = 500)
Running 'url_resolve_nested' benchmark ...
Min: 0.000046 -> 0.000038: 1.2179x faster
Avg: 0.000075 -> 0.000052: 1.4505x faster
Not significant
Stddev: 0.00059 -> 0.00024: 2.4300x smaller (N = 500)
Running 'model_creation' benchmark ...
Min: 0.000071 -> 0.000065: 1.1058x faster
Avg: 0.000079 -> 0.000073: 1.0876x faster
Significant (t=2.786580)
Stddev: 0.00003 -> 0.00004: 1.1518x larger (N = 500)
Running 'query_order_by' benchmark ...
Min: 0.000146 -> 0.000128: 1.1407x faster
Avg: 0.000154 -> 0.000138: 1.1206x faster
Significant (t=14.021341)
Stddev: 0.00002 -> 0.00002: 1.2540x larger (N = 500)
Running 'startup' benchmark ...
Skipped: Django 1.9 and later has changed app loading. This benchmark needs fixing anyway.
Running 'form_clean' benchmark ...
Min: 0.000005 -> 0.000004: 1.4613x faster
Avg: 0.000006 -> 0.000004: 1.3654x faster
Significant (t=12.763128)
Stddev: 0.00000 -> 0.00000: 1.1666x larger (N = 500)
Running 'locale_from_request' benchmark ...
Min: 0.000097 -> 0.000108: 1.1090x slower
Avg: 0.000108 -> 0.000120: 1.1178x slower
Significant (t=-3.057677)
Stddev: 0.00007 -> 0.00006: 1.1186x smaller (N = 500)
Running 'query_exists' benchmark ...
Min: 0.000273 -> 0.000234: 1.1698x faster
Avg: 0.000290 -> 0.000248: 1.1686x faster
Significant (t=39.518859)
Stddev: 0.00002 -> 0.00002: 1.2025x smaller (N = 500)
Running 'query_values_10000' benchmark ...
Min: 0.005601 -> 0.005298: 1.0571x faster
Avg: 0.006023 -> 0.005691: 1.0583x faster
Significant (t=6.167352)
Stddev: 0.00082 -> 0.00088: 1.0752x larger (N = 500)
Running 'query_exclude' benchmark ...
Min: 0.000159 -> 0.000140: 1.1367x faster
Avg: 0.000165 -> 0.000149: 1.1020x faster
Significant (t=19.643154)
Stddev: 0.00001 -> 0.00001: 1.2636x larger (N = 500)
Running 'query_raw' benchmark ...
Min: 0.005764 -> 0.004630: 1.2450x faster
Avg: 0.006169 -> 0.004881: 1.2638x faster
Significant (t=20.996453)
Stddev: 0.00109 -> 0.00083: 1.3105x smaller (N = 500)
Running 'url_resolve' benchmark ...
Min: 0.004928 -> 0.004597: 1.0721x faster
Avg: 0.005217 -> 0.004716: 1.1063x faster
Significant (t=46.893945)
Stddev: 0.00022 -> 0.00010: 2.2192x smaller (N = 500)
Running 'model_save_new' benchmark ...
Min: 0.003404 -> 0.003012: 1.1301x faster
Avg: 0.003494 -> 0.003105: 1.1251x faster
Significant (t=45.888484)
Stddev: 0.00014 -> 0.00013: 1.0298x smaller (N = 500)
Running 'query_all' benchmark ...
Min: 0.007971 -> 0.007085: 1.1250x faster
Avg: 0.009091 -> 0.008147: 1.1159x faster
Significant (t=7.583074)
Stddev: 0.00183 -> 0.00210: 1.1518x larger (N = 500)
```

View File

@ -0,0 +1,203 @@
# SQL
SQL Tuning is usually the realm of experienced Database Admins, as it can be full of missteps leading to worse performance. It is _extremely_ important that you take it slowly, make one change at a time with dedicated research and test before and after.
Before you start down this path its best to update [MariaDB](https://mariadb.org/download/?t=repo-config) / MySQL. Performance Schemas, some default tuning and other general performance improvements are only available on new versions. You must also allow your server to run for 24 hours at least to gather accurate data.
## MySQLTuner
[MySQLTuner](https://github.com/major/MySQLTuner-perl) is a Perl script that will analyze inbuilt metrics and spit out recommendations.
### [performance_schema](https://mariadb.com/kb/en/performance-schema-system-variables/#performance_schema)
This should be ON for 24 hours before applying any recommendations, then can be turned _OFF_ to save Memory while its not needed.
```bash
-------- Performance schema ------------------------------------------------------------------------
[--] Performance_schema is activated.
[--] Memory used by Performance_schema: 105.7M
[--] Sys schema is installed.
# 105M could be significant depending on your hardware
```
## SQL Variables
### [skip-name-resolve](https://mariadb.com/kb/en/server-system-variables/#skip_name_resolve)
While on, SQL will perform a dns resolve for all connections, if your database is connected via IP, this will save you a handful of cpu cycles per connection.
Note you must use 127.0.0.1 for localhost connections, and all entries in GRANT tables (permissions), must use IP addresses.
### [table_definition_cache](https://mariadb.com/kb/en/server-system-variables/#table_definition_cache)
Will usually need to be expanded on installs with many extensions
Most installs should cache all their tables, but if your hit rate is still quite high, you may have a lot of rarely used tables that you don't need to waste memory caching.
```bash
[OK] Table cache hit rate: 63% (2K hits / 4K requests).
# Only 63% of our queries are using this cache
table_definition_cache (400) > 567 or -1 (autosizing if supported)
# Here We have 567 tables, but a default cache of only 400.
```
```bash
[OK] Table cache hit rate: 99% (372M hits / 372M requests)
[OK] table_definition_cache (600) is greater than number of tables (567)
# Much better
```
### [innodb_buffer_pool_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_buffer_pool_size)
This is in short, the amount of memory assigned to store data for faster reads. If you are memory starved you should not increase this variable regardless of the suggestions of this tool. Pushing SQL cache to pagefile will not result in faster queries.
If you are not memory starved, you can wind this up to the amount of total data you have to store it all in memory. This would be a significant performance increase for larger installs on dedicated hardware with memory to spare.
```bash
[!!] InnoDB buffer pool / data size: 128.0M / 651.6M
# I have 651mb of _possible_ data to cache.
# We won't and shouldn't cache it all unless we have excess memory to spare.
...
[!!] InnoDB Read buffer efficiency: 0% (-2019 hits / 0 total)
# A low ratio here would suggest more Memory can be used effectively.
# A high ratio might mean we have most of our regularly used data cached already
```
### [innodb_log_buffer_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_buffer_size) / [innodb_log_file_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_file_size)
[innodb_log_file_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_file_size) This is your _write_ log, used to redo any commits in the event of a crash. MySQLTuner recommends this be 1/4 of your innodb_buffer_pool / read buffer. I would not lower this past the default size.
[innodb_log_buffer_size](https://mariadb.com/kb/en/innodb-system-variables/#innodb_log_buffer_size) This is the memory buffer for the write log. Larger transactions will benefit from a larger setting.
```bash
[!!] Ratio InnoDB log file size / InnoDB Buffer pool size (75%): 96.0M \* 1 / 128.0M should be equal to 25%
# Here our write log file is 75% of our read buffer, but 96MB is the default so we probably wont shrink it further
...
[OK] InnoDB Write Log efficiency: 99.11% (23167614 hits / 23375465 total) # Our transactions are typically not large enough to exhaust the write log buffer,
[OK] InnoDB log waits: 0.00% (0 waits / 207851 writes)
```
### [innodb_file_per_table](https://mariadb.com/kb/en/innodb-system-variables/#innodb_file_per_table)
This is not for performance, but for file system utilization and ease of use. While off all tables are stored in a single monolith file, as opposed to individual files. This is deprecated and set to ON in MariaDB 11.x
```bash
[OK] InnoDB File per table is activated
```
### [join_buffer_size](https://mariadb.com/kb/en/server-system-variables/#join_buffer_size)
It is always better to optimize a table with indexes, if you have valuable performance data and analysis please reach out to either the Alliance Auth or Community dev responsible for the data that could benefit from indexes. MySQLTuner will likely recommend increasing this number for as long as there are any queries that could benefit, regardless of their resulting performance impact.
Also keep in mind this is _per thread_, if you have a potential 200 connections, 256KB * 200 = 50MB, scaling this setting out too far can result in more memory use than expected.
```bash
[!!] Joins performed without indexes: 67646
```
```bash
[OK] No joins without indexes
# An ideal scenario. With well designed apps this is possible with a default join buffer.
```
### [tmp_table_size](https://mariadb.com/kb/en/server-system-variables/#tmp_table_size) / [max_heap_table_size](https://mariadb.com/kb/en/server-system-variables/#max_heap_table_size)
If a temporary table must be created due to a lack of other optimizations or large queries, it may only be stored in memory under this size. Any larger and it is performed on disk reducing performance.
tmp_table_size and max_heap_table_size should be increased together.
```bash
[!!] Temporary tables created on disk: 32% (775 on disk / 2K total)
# 32% of my temp tables are performed on disk. If you increase this size, monitor if your performance improves.
# If it does not you may have data of a certain size that is impractical to cache, and you can reclaim this memory.
```
```bash
[OK] Temporary tables created on disk: 0% (5K on disk / 4M total)
# Here only a miniscule amount of my temp tables are done on disk. No action required
```
### key_buffer_size
Index buffer for MyISAM tables, If you use no or very little data in MyISAM tables. You may reclaim some memory here
In this example we still have some MyISAM tables, you may have none
```bash
[--] General MyIsam metrics:
[--] +-- Total MyISAM Tables : 67
[--] +-- Total MyISAM indexes : 7.1M
[--] +-- KB Size :8.0M
[--] +-- KB Used Size :1.5M
[--] +-- KB used :18.3%
[--] +-- Read KB hit rate: 0% (0 cached / 0 reads)
[--] +-- Write KB hit rate: 0% (0 cached / 0 writes)
[!!] Key buffer used: 18.3% (1.5M used / 8.0M cache) # We have only filled 1.5M of the 8 assigned
[OK] Key buffer size / total MyISAM indexes: 8.0M/7.1M # This is the max theoretical buffer to cache all my indexes
Variables to adjust:
key_buffer_size (~ 1M)
# Tuner has seen that we barely use this buffer and it can be shrunk, if you care about its impact don't lower this below your total indexes.
```
### [aria_pagecache_buffer_size](https://mariadb.com/kb/en/aria-system-variables/#aria_pagecache_buffer_size)
Index and data buffer for Aria tables, If you use no or very little data in Aria tables. You may reclaim some memory here
```bash
-------- Aria Metrics ------------------------------------------------------------------------------
[--] Aria Storage Engine is enabled.
[OK] Aria pagecache size / total Aria indexes: 128.0M/328.0K # i use a fraction of my aria buffer since i have no aria tables.
[OK] Aria pagecache hit rate: 99.9% (112K cached / 75 reads) # Aria is used internally for MariaDB, so you still want an incredibly high ratio here.
```
## Swappiness
Swappiness is not an SQL variable but part of your system kernel. Swappiness controls how much free memory a server "likes" to have at any given time, and how frequently it shifts data to swapfile in order to free up memory. Desktop operating systems will have this value set quite high, whereas servers are less aggressive with their swapfile.
Database workloads especially benefit from having their caches stay in memory and will recommend values under 10 for a dedicated database server. 10 is a good compromise for a mixed use server with adequate memory.
If your server is memory starved, leave swapfile aggressive to ensure it is moving memory around as needed.
```bash
joel@METABOX:~/aa_dev$ free -m
total used free shared buff/cache available
Mem: 15998 1903 13372 2 722 13767
Swap: 4096 1404 2691
# Here we can see a lot of memory page (1404MB) sitting in swap while there is free memory (13372MB) available
```
```bash
[root@auth ~]# free -m
total used free shared buff/cache available
Mem: 738 611 59 1 68 35
Swap: 2047 1014 1033
# Here we can see a memory starved server highly utilizing swap already. I wouldn't mess with it too much. (vm.swappiness is 30)
```
```bash
[root@mysql ~]# free -m
total used free shared buff/cache available
Mem: 738 498 95 7 145 120
Swap: 2047 289 1758
# Here we can see a dedicated single use Database Server, Swappiness is 10 here because we have been careful not to starve it of memory and there is low potential to impact other applications
```
```bash
[--] Information about kernel tuning:
...
[--] vm.swappiness = 30
[xx] Swappiness is < 10.
...
vm.swappiness <= 10 (echo 10 > /proc/sys/vm/swappiness) or vm.swappiness=10 in /etc/sysctl.conf
```
## Max Asynchronous IO
Unless you are still operating on spinning rust (Hard Disk Drives), or an IO limited VPS, you can likely increase this value. Database workloads appreciate the additional scaling.
```bash
[--] Information about kernel tuning:
[--] fs.aio-max-nr = 65536
...
fs.aio-max-nr > 1M (echo 1048576 > /proc/sys/fs/aio-max-nr) or fs.aio-max-nr=1048576 in /etc/sysctl.conf
```