Repository: WeblateOrg/weblate

Issue:
A project with 1000 components is very slow
In a project with a large number of components, individual segments load tragically. My project has about 1000 components, it has a lot to do with speed in all components. For comparison, I have created a new project with the same files and it loads quickly. Unfortunately, I cannot afford many projects because propagation does not work between projects.
For speed comparison, I put the same files in a test project, one is shared from a huge project.
[Link](https://weblate.eso-spolszczenie.eu/projects/101286772-test-propagacji-miedzy-projektami/)


Discussion:
This issue looks more like a support question than an issue. We strive to answer these reasonably fast, but [purchasing the support subscription](https://weblate.org/support/) is not only more responsible and faster for your business but also makes Weblate stronger. In case your question is already answered, [making a donation](https://weblate.org/donate/) is the right way to say thank you!
We definitely need to re-introduce pagination here to avoid loading all the components in such cases.

Resolving patch:
diff --git a/weblate/trans/views/basic.py b/weblate/trans/views/basic.py
--- a/weblate/trans/views/basic.py
+++ b/weblate/trans/views/basic.py
@@ -56,6 +56,7 @@
 from weblate.utils.stats import GhostProjectLanguageStats, prefetch_stats
 from weblate.utils.views import (
     get_component,
+    get_paginator,
     get_project,
     get_translation,
     optional_form,
@@ -138,7 +139,10 @@ def show_project(request, project):
         obj.change_set.prefetch().order().filter(action=Change.ACTION_ANNOUNCEMENT)[:10]
     )
 
-    all_components = obj.child_components.filter_access(user).prefetch().order()
+    all_components = prefetch_stats(
+        obj.child_components.filter_access(user).prefetch().order()
+    )
+    all_components = get_paginator(request, all_components)
     for component in all_components:
         component.is_shared = None if component.project == obj else component.project
 
@@ -164,7 +168,7 @@ def show_project(request, project):
         ),
     )
 
-    components = prefetch_tasks(prefetch_stats(all_components))
+    components = prefetch_tasks(all_components)
 
     return render(
         request,
diff --git a/weblate/trans/views/dashboard.py b/weblate/trans/views/dashboard.py
--- a/weblate/trans/views/dashboard.py
+++ b/weblate/trans/views/dashboard.py
@@ -41,6 +41,7 @@
 from weblate.trans.util import render
 from weblate.utils import messages
 from weblate.utils.stats import prefetch_stats
+from weblate.utils.views import get_paginator
 
 
 def translation_prefetch_tasks(translations):
@@ -274,6 +275,7 @@ def dashboard_user(request):
                 component__project__in=user.watched_projects
             )
         )
+        usersubscriptions = get_paginator(request, usersubscriptions)
 
         if user.profile.hide_completed:
             usersubscriptions = get_untranslated(usersubscriptions)
diff --git a/weblate/utils/views.py b/weblate/utils/views.py
--- a/weblate/utils/views.py
+++ b/weblate/utils/views.py
@@ -38,6 +38,16 @@
 from weblate.utils import messages
 from weblate.vcs.git import LocalRepository
 
+SORT_KEYS = {
+    "name": lambda x: x.name if hasattr(x, "name") else x.component.name,
+    "translated": lambda x: x.stats.translated_percent,
+    "untranslated": lambda x: x.stats.todo,
+    "untranslated_words": lambda x: x.stats.todo_words,
+    "checks": lambda x: x.stats.allchecks,
+    "suggestions": lambda x: x.stats.suggestions,
+    "comments": lambda x: x.stats.comments,
+}
+
 
 def optional_form(form, perm_user, perm, perm_obj, **kwargs):
     if not perm_user.has_perm(perm, perm_obj):
@@ -69,10 +79,28 @@ def get_page_limit(request, default):
     return page, limit
 
 
+def sort_objects(object_list, sort_by: str):
+    if sort_by.startswith("-"):
+        sort_key = sort_by[1:]
+        reverse = True
+    else:
+        sort_key = sort_by
+        reverse = False
+    try:
+        key = SORT_KEYS[sort_key]
+    except KeyError:
+        return object_list, None
+    return sorted(object_list, key=key, reverse=reverse), sort_by
+
+
 def get_paginator(request, object_list, default_page_limit=100):
     """Return paginator and current page."""
     page, limit = get_page_limit(request, default_page_limit)
+    sort_by = request.GET.get("sort_by")
+    if sort_by:
+        object_list, sort_by = sort_objects(object_list, sort_by)
     paginator = Paginator(object_list, limit)
+    paginator.sort_by = sort_by
     try:
         return paginator.page(page)
     except EmptyPage:


Test patch: