diff --git a/integreat_cms/cms/templates/dashboard/_todo_dashboard_widget.html b/integreat_cms/cms/templates/dashboard/_todo_dashboard_widget.html index 15e8b244b8..b376b1393c 100644 --- a/integreat_cms/cms/templates/dashboard/_todo_dashboard_widget.html +++ b/integreat_cms/cms/templates/dashboard/_todo_dashboard_widget.html @@ -30,5 +30,8 @@ {% include "dashboard/todo_dashboard_rows/_automatically_saved_pages_row.html" %} {% include "dashboard/todo_dashboard_rows/_drafted_pages_row.html" %} {% endif %} + {% if perms.cms.change_page %} + {% include "dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html" %} + {% endif %} {% endblock collapsible_box_content %} diff --git a/integreat_cms/cms/templates/dashboard/todo_dashboard_rows/_missing_translations_row.html b/integreat_cms/cms/templates/dashboard/todo_dashboard_rows/_missing_translations_row.html new file mode 100644 index 0000000000..29cbfafe6d --- /dev/null +++ b/integreat_cms/cms/templates/dashboard/todo_dashboard_rows/_missing_translations_row.html @@ -0,0 +1,38 @@ +{% extends "../_todo_dashboard_row.html" %} +{% load i18n %} +{% block todo_dashboard_icon %} + languages +{% endblock todo_dashboard_icon %} +{% block todo_dashboard_title_link %} + {% url 'translation_coverage' region_slug=request.region.slug %} +{% endblock todo_dashboard_title_link %} +{% block todo_dashboard_title %} + {% translate "Outdated and missing translations" %} +{% endblock todo_dashboard_title %} +{% block todo_dashboard_number %} + {% with total=number_of_missing_translations %} + {{ block.super }} + {% endwith %} +{% endblock todo_dashboard_number %} +{% block todo_dashboard_description %} + {% if number_of_missing_translations > 0 %} + {% blocktranslate trimmed %} + Your pages currently have {{ number_of_missing_translations }} pages that have an outdated or no translation. + In order for the users to benefit from your content you should translate them or have them translated. + {% endblocktranslate %} + {% else %} + {% blocktranslate trimmed %} + At the moment all pages have up-to-date translations. Good job! + {% endblocktranslate %} + {% endif %} +{% endblock todo_dashboard_description %} +{% block todo_dashboard_button_link %} + {% if outdated_pages %} + + {% translate "Go to
translation coverage" %} +
+ {% else %} + + {% endif %} +{% endblock todo_dashboard_button_link %} diff --git a/integreat_cms/cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html b/integreat_cms/cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html new file mode 100644 index 0000000000..ac0e295a54 --- /dev/null +++ b/integreat_cms/cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html @@ -0,0 +1,53 @@ +{% extends "../_todo_dashboard_row.html" %} +{% load i18n %} +{% block todo_dashboard_ajax_url %} + {{ translation_coverage_ajax }} +{% endblock todo_dashboard_ajax_url %} +{% block todo_dashboard_id %} + translation-coverage +{% endblock todo_dashboard_id %} +{% block todo_dashboard_icon %} + languages +{% endblock todo_dashboard_icon %} +{% block todo_dashboard_title_link %} + {% url 'translation_coverage' region_slug=request.region.slug %} +{% endblock todo_dashboard_title_link %} +{% block todo_dashboard_title %} + {% translate "Outdated and missing translations" %} +{% endblock todo_dashboard_title %} +{% block todo_dashboard_number %} + {% with total=number_of_missing_or_outdated_translations %} + {{ block.super }} + {% endwith %} +{% endblock todo_dashboard_number %} +{% block todo_dashboard_description %} + + +
+ {% blocktranslate trimmed %} + We are loading your outdated and missing translations in the background. Please be patient. + {% endblocktranslate %} +
+{% endblock todo_dashboard_description %} +{% block todo_dashboard_button_link %} + + +{% endblock todo_dashboard_button_link %} diff --git a/integreat_cms/cms/urls/protected.py b/integreat_cms/cms/urls/protected.py index 4e3ae8c9b8..0536de7aa9 100644 --- a/integreat_cms/cms/urls/protected.py +++ b/integreat_cms/cms/urls/protected.py @@ -584,7 +584,12 @@ "broken-links/", dashboard.DashboardView.get_broken_links_context, name="get_broken_links_ajax", - ) + ), + path( + "translation-coverage/", + dashboard.DashboardView.get_translation_coverage_context, + name="get_translation_coverage_ajax", + ), ] ), ), diff --git a/integreat_cms/cms/views/dashboard/dashboard_view.py b/integreat_cms/cms/views/dashboard/dashboard_view.py index 8444b81573..c7a4f3a030 100644 --- a/integreat_cms/cms/views/dashboard/dashboard_view.py +++ b/integreat_cms/cms/views/dashboard/dashboard_view.py @@ -61,6 +61,10 @@ def get_context_data(self, **kwargs: Any) -> dict[str, Any]: "get_broken_links_ajax", kwargs={"region_slug": self.request.region.slug}, ), + "translation_coverage_ajax": reverse( + "get_translation_coverage_ajax", + kwargs={"region_slug": self.request.region.slug}, + ), } ) @@ -242,3 +246,31 @@ def get_drafted_pages( "drafted_pages": drafted_pages, "single_drafted_page": single_drafted_page, } + + @json_response + # pylint: disable=unused-argument, disable=no-self-argument + def get_translation_coverage_context( + request: HttpRequest, region_slug: str + ) -> JsonResponse: + r""" + Extend context by info on translation coverage of pages + + :return: Dictionary containing the context for translation coverage of pages in a region + """ + non_archived_pages = request.region.non_archived_pages + language_count = len(request.region.languages) + possible_translations = non_archived_pages.count() * language_count + + all_translations = PageTranslation.objects.filter( + page__in=non_archived_pages + ).only("pk") + non_outdated_translations = sum( + 1 for translation in all_translations if not translation.is_outdated + ) + + return JsonResponse( + data={ + "number_of_missing_or_outdated_translations": possible_translations + - non_outdated_translations + } + ) diff --git a/integreat_cms/locale/de/LC_MESSAGES/django.po b/integreat_cms/locale/de/LC_MESSAGES/django.po index 5ca752db97..13aea1a632 100644 --- a/integreat_cms/locale/de/LC_MESSAGES/django.po +++ b/integreat_cms/locale/de/LC_MESSAGES/django.po @@ -5718,6 +5718,32 @@ msgid "At the moment all pages are ready for machine translation. Good job!" msgstr "" "Aktuell sind alle Seiten bereit zur maschinellen Übersetzung. Gute Arbeit!" +#: cms/templates/dashboard/todo_dashboard_rows/_missing_translations_row.html +#: cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html +msgid "Outdated and missing translations" +msgstr "Veraltete und fehlende Übersetzungen" + +#: cms/templates/dashboard/todo_dashboard_rows/_missing_translations_row.html +#, python-format +msgid "" +"Your pages currently have %(number_of_missing_translations)s pages that have an outdated or no translation. In order for the users to benefit " +"from your content you should translate them or have them translated." +msgstr "" +"Ihre Inhalte haben momentan %(number_of_missing_translations)s Seiten " +"mit fehlender oder veralteter Übersetzung. Damit die Nutzer:innen von Ihren " +"Inhalten profitieren können, sollten Sie diese übersetzen (lassen)." + +#: cms/templates/dashboard/todo_dashboard_rows/_missing_translations_row.html +#: cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html +msgid "At the moment all pages have up-to-date translations. Good job!" +msgstr "Aktuell haben alle Ihre Seiten aktuelle Übersetzungen. Gute Arbeit!" + +#: cms/templates/dashboard/todo_dashboard_rows/_missing_translations_row.html +#: cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html +msgid "Go to
translation coverage" +msgstr "Zum Bericht" + #: cms/templates/dashboard/todo_dashboard_rows/_outdated_pages_row.html msgid "Outdated pages" msgstr "Veraltete Seiten" @@ -5778,6 +5804,24 @@ msgstr "" msgid "At the moment there is no page waiting for approval. Good job!" msgstr "Aktuell liegen keine Seiten zur Freigabe vor. Gute Arbeit!" +#: cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html +msgid "" +"Your pages currently have pages that have an outdated or no " +"translation. In order for the users to benefit from your content you should " +"translate them or have them translated." +msgstr "" +"Ihre Inhalte haben momentan Seiten mit fehlender oder " +"veralteter Übersetzung. Damit die Nutzer:innen von Ihren Inhalten " +"profitieren können, sollten Sie diese übersetzen (lassen)." + +#: cms/templates/dashboard/todo_dashboard_rows/number_of_missing_or_outdated_translations_row.html +msgid "" +"We are loading your outdated and missing translations in the background. " +"Please be patient." +msgstr "" +"Wir laden im Hintergrund gerade Ihre kaputten Links. Bitte haben Sie noch " +"ein wenig Geduld." + #: cms/templates/emails/_base_email.html #: cms/templates/emails/password_reset_email.txt #: cms/templates/emails/welcome_email.txt @@ -11285,6 +11329,25 @@ msgstr "" #~ msgid "Contents" #~ msgstr "Inhalte" +#~ msgid "" +#~ "We are loading your translation coverage in the background. Please be " +#~ "patient." +#~ msgstr "" +#~ "Wir laden im Hintergrund gerade Ihre veralteten und fehlenden " +#~ "Übersetzungen. Bitte haben Sie noch ein wenig Geduld." + +#, python-format +#~ msgid "" +#~ "Your pages currently have " +#~ "%(number_of_missing_or_outdated_translations)s pages that have an " +#~ "outdated or no translation. In order for the users to benefit from your " +#~ "content you should translate them or have them translated." +#~ msgstr "" +#~ "Ihre Inhalten haben aktuell " +#~ "%(number_of_missing_or_outdated_translations)s Seiten mit " +#~ "fehlender oder veralteter Übersetzung. Damit die Nutzer:innen von Ihren " +#~ "Inhalten profitieren können, sollten Sie diese übersetzen (lassen)." + #~ msgid "View location" #~ msgstr "Ort ansehen" @@ -12568,9 +12631,6 @@ msgstr "" #~ msgid "Translations missing" #~ msgstr "Fehlende Übersetzungen" -#~ msgid "Translation Coverage" -#~ msgstr "Abdeckung der Übersetzungen" - #~ msgid "Settings for" #~ msgstr "Einstellungen für" diff --git a/integreat_cms/static/src/index.ts b/integreat_cms/static/src/index.ts index b81aae6203..ff68c6c3a2 100644 --- a/integreat_cms/static/src/index.ts +++ b/integreat_cms/static/src/index.ts @@ -103,6 +103,7 @@ import "./js/menu"; import "./js/poi-categories/poicategory-colors-icons"; import "./js/dashboard/broken-links"; +import "./js/dashboard/translation-coverage"; // IE11: fetch /* eslint-disable-next-line @typescript-eslint/no-var-requires */ diff --git a/integreat_cms/static/src/js/dashboard/translation-coverage.ts b/integreat_cms/static/src/js/dashboard/translation-coverage.ts new file mode 100644 index 0000000000..ed41d473d2 --- /dev/null +++ b/integreat_cms/static/src/js/dashboard/translation-coverage.ts @@ -0,0 +1,84 @@ +import { getCsrfToken } from "../utils/csrf-token"; + +type Content = { + number_of_missing_or_outdated_translations: number; +}; + +const getContent = async (url: string): Promise => { + const response = await fetch(url, { + method: "POST", + headers: { + "X-CSRFToken": getCsrfToken(), + }, + }); + return response.json(); +}; + +const showAllTotalNumbers = () => { + const elements = document.querySelectorAll(".total-results"); + + elements.forEach((element) => { + if (!element.closest("#translation-coverage")) { + const el = element; + el.classList.remove("hidden"); + } + }); +}; + +window.addEventListener("load", async () => { + showAllTotalNumbers(); + + const translationCoverageElement = document.getElementById("translation-coverage"); + + if (!translationCoverageElement) { + return; + } + + const url = translationCoverageElement.dataset.url; + const hideWaitingMessage = () => { + translationCoverageElement.querySelector(".waiting-message").classList.add("hidden"); + }; + + const showSuccessMessage = () => { + translationCoverageElement.querySelector(".success-message").classList.remove("hidden"); + }; + + const showSuccessIcon = () => { + translationCoverageElement.querySelector(".success-icon").classList.remove("hidden"); + }; + + const showDescription = (affectedPageTitle: string) => { + translationCoverageElement.querySelector(".todo-message").classList.remove("hidden"); + (translationCoverageElement.querySelector(".todo-message b") as HTMLElement).innerText = affectedPageTitle; + }; + + const showNumberOfPagesElement = () => { + translationCoverageElement.querySelector(".total-results").classList.remove("hidden"); + }; + + const updateNumberOfPages = (numberOfPages: number) => { + (translationCoverageElement.querySelector(".total-results span") as HTMLElement).innerText = + numberOfPages.toString(); + }; + + const showButton = () => { + translationCoverageElement.querySelector(".todo-button").classList.remove("hidden"); + }; + + if (url) { + console.log(url); + const json = await getContent(url); + console.log(json); + hideWaitingMessage(); + showNumberOfPagesElement(); + if (json.number_of_missing_or_outdated_translations > 0) { + showDescription(String(json.number_of_missing_or_outdated_translations)); + updateNumberOfPages(json.number_of_missing_or_outdated_translations); + showButton(); + } else { + showSuccessMessage(); + showSuccessIcon(); + updateNumberOfPages(0); + } + } +});