Add ability to translate tags and content warnings

This commit is contained in:
rubenwardy 2024-06-07 05:28:57 +01:00
parent 7d00a5b969
commit d2c5779301
10 changed files with 73 additions and 21 deletions

@ -217,11 +217,12 @@ def download(package):
return redirect(release.get_download_url())
def makeLabel(obj):
if obj.description:
return "{}: {}".format(obj.title, obj.description)
def make_label(obj: Tag | ContentWarning):
translated = obj.get_translated()
if translated["description"]:
return "{}: {}".format(translated["title"], translated["description"])
else:
return obj.title
return translated["title"]
class PackageForm(FlaskForm):
@ -232,8 +233,8 @@ class PackageForm(FlaskForm):
dev_state = SelectField(lazy_gettext("Maintenance State"), [InputRequired()], choices=PackageDevState.choices(with_none=True), coerce=PackageDevState.coerce)
tags = QuerySelectMultipleField(lazy_gettext('Tags'), query_factory=lambda: Tag.query.order_by(db.asc(Tag.name)), get_pk=lambda a: a.id, get_label=makeLabel)
content_warnings = QuerySelectMultipleField(lazy_gettext('Content Warnings'), query_factory=lambda: ContentWarning.query.order_by(db.asc(ContentWarning.name)), get_pk=lambda a: a.id, get_label=makeLabel)
tags = QuerySelectMultipleField(lazy_gettext('Tags'), query_factory=lambda: Tag.query.order_by(db.asc(Tag.name)), get_pk=lambda a: a.id, get_label=make_label)
content_warnings = QuerySelectMultipleField(lazy_gettext('Content Warnings'), query_factory=lambda: ContentWarning.query.order_by(db.asc(ContentWarning.name)), get_pk=lambda a: a.id, get_label=make_label)
license = QuerySelectField(lazy_gettext("License"), [DataRequired()], allow_blank=True, query_factory=lambda: License.query.order_by(db.asc(License.name)), get_pk=lambda a: a.id, get_label=lambda a: a.name)
media_license = QuerySelectField(lazy_gettext("Media License"), [DataRequired()], allow_blank=True, query_factory=lambda: License.query.order_by(db.asc(License.name)), get_pk=lambda a: a.id, get_label=lambda a: a.name)

@ -906,6 +906,13 @@ class ContentWarning(db.Model):
regex = re.compile("[^a-z_]")
self.name = regex.sub("", self.title.lower().replace(" ", "_"))
def get_translated(self):
# Translations are automated on dynamic data using `extract_translations.py`
return {
"title": gettext(self.title),
"description": gettext(self.description),
}
def as_dict(self):
description = self.description if self.description != "" else None
return { "name": self.name, "title": self.title, "description": description }
@ -931,6 +938,13 @@ class Tag(db.Model):
regex = re.compile("[^a-z_]")
self.name = regex.sub("", self.title.lower().replace(" ", "_"))
def get_translated(self):
# Translations are automated on dynamic data using `extract_translations.py`
return {
"title": gettext(self.title),
"description": gettext(self.description),
}
def as_dict(self):
description = self.description if self.description != "" else None
return {

@ -60,9 +60,9 @@ class QueryBuilder:
if len(self.tags) == 0:
ret = package_type
elif len(self.tags) == 1:
ret = self.tags[0].title + " " + package_type
ret = self.tags[0].get_translated()["title"] + " " + package_type
else:
tags = ", ".join([tag.title for tag in self.tags])
tags = ", ".join([tag.get_translated()["title"] for tag in self.tags])
ret = f"{tags} - {package_type}"
if self.search:

@ -2,7 +2,7 @@
{% block title %}
{% if tag %}
Edit {{ tag.title }}
Edit {{ tag.get_translated().title }}
{% else %}
New tag
{% endif %}

@ -166,9 +166,9 @@
{% set tag = pair[1] %}
<a class="btn btn-sm btn-secondary m-1" rel="nofollow"
title="{{ tag.description or '' }}"
title="{{ tag.get_translated().description or '' }}"
href="{{ url_for('packages.list_all', tag=tag.name) }}">
{{ tag.title }}
{{ tag.get_translated().title }}
<span class="badge rounded-pill bg-light text-dark ms-1">{{ count }}</span>
</a>
{% endfor %}

@ -31,16 +31,16 @@
{% if tag in selected_tags %}
<a class="btn btn-sm btn-primary m-1" rel="nofollow"
title="{{ tag.description or '' }}"
title="{{ tag.get_translated().description or '' }}"
href="{{ url_set_query(page=1, _remove={ 'tag': tag.name }) }}">
{{ tag.title }}
{{ tag.get_translated().title }}
<span class="badge rounded-pill bg-light text-dark ms-1">{{ count }}</span>
</a>
{% else %}
<a class="btn btn-sm btn-secondary m-1" rel="nofollow"
title="{{ tag.description or '' }}"
title="{{ tag.get_translated().description or '' }}"
href="{{ url_set_query(page=1, _add={ 'tag': tag.name }) }}">
{{ tag.title }}
{{ tag.get_translated().title }}
<span class="badge rounded-pill bg-light text-dark ms-1">{{ count }}</span>
</a>
{% endif %}

@ -163,11 +163,11 @@
{{ _("Work in Progress") }}
</span>
{% endif %}
{% for t in package.tags %}
{% for tag in package.tags %}
<a class="badge bg-primary" rel="nofollow"
title="{{ t.description or '' }}"
href="{{ url_for('packages.list_all', tag=t.name) }}">
{{ t.title }}
title="{{ tag.get_translated().description or '' }}"
href="{{ url_for('packages.list_all', tag=tag.name) }}">
{{ tag.get_translated().title }}
</a>
{% endfor %}
</p>

@ -57,7 +57,7 @@
{% for tag in package.tags %}
<a class="badge bg-primary me-1"
href="{{ url_set_query(_add={ 'tag': tag.name }) }}">
{{ tag.title }}
{{ tag.get_translated().title }}
</a>
{% endfor %}
<!-- <a class="badge bg-secondary add-btn px-2" href="#">

@ -261,7 +261,7 @@ def package_info_as_hypertext(package: Package, formspec_version: int = 7):
body += "</b>\n\n"
add_value(gettext("Type"), package.type.text)
add_list(gettext("Tags"), [tag.title for tag in package.tags])
add_list(gettext("Tags"), [tag.get_translated()["title"] for tag in package.tags])
if package.type != PackageType.GAME:
def make_game_link(game):

37
utils/extract_translations.py Executable file

@ -0,0 +1,37 @@
#!/usr/bin/python
import subprocess
from typing import List
import requests
base_url = "https://content.minetest.net"
translations = set()
def add_translations_from_api_array(path: str, fields: List[str]):
print(f"Extracting translations from {path}")
url = base_url + path
req = requests.get(url)
json = req.json()
for i, row in enumerate(json):
for field in fields:
if row.get(field) is not None:
translations.add(row[field])
add_translations_from_api_array("/api/tags/", ["title", "description"])
add_translations_from_api_array("/api/content_warnings/", ["title", "description"])
with open("app/_translations.py", "w") as f:
f.write("# THIS FILE IS AUTOGENERATED: utils/extract_translations.py\n\n")
f.write("from flask_babel import gettext\n\n")
for translation in translations:
escaped = translation.replace('\n', '\\n').replace("\"", "\\\"")
f.write(f"gettext(\"{escaped}\")\n")
subprocess.run(["pybabel", "extract", "-F", "babel.cfg", "-k", "lazy_gettext", "-o", "translations/messages.pot", "."])
subprocess.run(["pybabel", "update", "-i", "translations/messages.pot", "-d", "translations", "--no-fuzzy-matching"])