diff --git a/app/blueprints/translate/__init__.py b/app/blueprints/translate/__init__.py
new file mode 100644
index 00000000..2a1dc83c
--- /dev/null
+++ b/app/blueprints/translate/__init__.py
@@ -0,0 +1,44 @@
+# ContentDB
+# Copyright (C) 2024 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+
+from flask import Blueprint, render_template, request
+
+from app.models import Package, PackageState, db, PackageTranslation
+
+bp = Blueprint("translate", __name__)
+
+
+@bp.route("/translate/")
+def translate():
+ query = Package.query.filter(
+ Package.state == PackageState.APPROVED,
+ Package.translations.any(PackageTranslation.language_id != "en"))
+
+ has_langs = request.args.getlist("has_lang")
+ for lang in has_langs:
+ query = query.filter(Package.translations.any(PackageTranslation.language_id == lang))
+
+ not_langs = request.args.getlist("not_lang")
+ for lang in not_langs:
+ query = query.filter(~Package.translations.any(PackageTranslation.language_id == lang))
+
+ supports_translation = (query
+ .order_by(Package.translation_url.is_(None), db.desc(Package.score))
+ .all())
+
+ return render_template("translate/index.html",
+ supports_translation=supports_translation, has_langs=has_langs, not_langs=not_langs)
diff --git a/app/template_filters.py b/app/template_filters.py
index e8f567a2..e430787f 100644
--- a/app/template_filters.py
+++ b/app/template_filters.py
@@ -18,7 +18,7 @@ from datetime import datetime as dt
from urllib.parse import urlparse
from flask import request, has_request_context
-from flask_babel import format_timedelta, gettext
+from flask_babel import format_timedelta, gettext, get_locale
from flask_login import current_user
from markupsafe import Markup
@@ -34,7 +34,7 @@ def inject_misc():
hide_nonfree = False
if has_request_context():
hide_nonfree = request.cookies.get("hide_nonfree") == "1"
- return dict(debug=app.debug, hide_nonfree=hide_nonfree)
+ return dict(debug=app.debug, hide_nonfree=hide_nonfree, locale=get_locale())
@app.context_processor
diff --git a/app/templates/base.html b/app/templates/base.html
index 3a2371f7..667481ab 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -255,6 +255,7 @@
{{ _("Threads") }}
{{ _("Collections") }}
{{ _("Support Packages") }}
+ {{ _("Translate Packages") }}
{{ _("Source Code") }}
diff --git a/app/templates/translate/index.html b/app/templates/translate/index.html
new file mode 100644
index 00000000..fe30ed0e
--- /dev/null
+++ b/app/templates/translate/index.html
@@ -0,0 +1,90 @@
+{% extends "base.html" %}
+
+{% block title -%}
+ {{ _("Find packages to translate") }}
+{%- endblock %}
+
+{% block description -%}
+ {{ _("Help make Minetest more accessible by translating packages into other languages.") }}
+{% endblock %}
+
+{% macro render_packages(packages) %}
+
+ {% for package in packages %}
+ -
+
+
+ {% else %}
+ -
+ {{ _("No packages available") }}
+
+ {% endfor %}
+
+{% endmacro %}
+
+
+{% block content %}
+ {{ self.title() }}
+
+ {{ self.description() }}
+
+
+ {{ _("ContentDB") }}
+
+
+ {{ _("Help translate ContentDB") }}
+
+
+
+ {{ _("Packages that support translation") }}
+ {% if locale and locale.language != "en" %}
+
+
+ {{ _("Only show packages with %(lang)s translation", lang=locale.get_language_name(locale)) }}
+
+
+ {{ _("Hide packages with %(lang)s translation", lang=locale.get_language_name(locale)) }}
+
+
+ {% endif %}
+ {{ render_packages(supports_translation) }}
+{% endblock %}
diff --git a/app/utils/flask.py b/app/utils/flask.py
index 3364dd20..d3998c1d 100644
--- a/app/utils/flask.py
+++ b/app/utils/flask.py
@@ -87,7 +87,15 @@ def url_set_query(**kwargs):
args = MultiDict(request.args)
for key, value in kwargs.items():
- if key == "_add":
+ if key == "_toggle":
+ for key2, value_to_add in value.items():
+ values = set(args.getlist(key2))
+ if value_to_add in values:
+ values.discard(value_to_add)
+ else:
+ values.add(value_to_add)
+ args.setlist(key2, list(values))
+ elif key == "_add":
for key2, value_to_add in value.items():
values = set(args.getlist(key2))
values.add(value_to_add)