Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve translation handling in JavaScript and TypeScript #2036

Merged
merged 11 commits into from
Nov 6, 2023
8 changes: 8 additions & 0 deletions evap/development/management/commands/translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@
def handle(self, *args, **options):
self.stdout.write('Executing "manage.py makemessages --locale=de --ignore=node_modules/*"')
call_command("makemessages", "--locale=de", "--ignore=node_modules/*")
call_command(

Check warning on line 12 in evap/development/management/commands/translate.py

View check run for this annotation

Codecov / codecov/patch

evap/development/management/commands/translate.py#L12

Added line #L12 was not covered by tests
"makemessages",
"--domain=djangojs",
"--extension=js,ts",
"--locale=de",
"--ignore=node_modules/*",
"--ignore=evap/static/js/*.min.js",
)
2 changes: 2 additions & 0 deletions evap/evaluation/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@

{% include 'footer.html' %}

<script src="{% url 'javascript-catalog' %}"></script>

<script type="text/javascript" src="{% static 'js/jquery-2.1.3.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/tom-select.complete.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/plugins/jquery.formset.js' %}"></script>
Expand Down
4 changes: 3 additions & 1 deletion evap/evaluation/templates/evap_evaluation_edit_js.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{% load static %}

{% if editable %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>
<script type="text/javascript">
rowChanged = function(row) {
name = $(row.find("select[id$=-contributor]")).find(":selected").text();
Expand Down
2 changes: 1 addition & 1 deletion evap/evaluation/templates/notebook.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ <h5 class="card-title m-0">
{% csrf_token %}
{{ notebook_form.notes }}
<div class="d-flex justify-content-center pt-3">
<button class="btn btn-primary" type="submit" data-errormessage="{% trans 'The server is not responding.' %}">
<button class="btn btn-primary" type="submit">
<span class="visible-if-ready">{% trans 'Save' %}</span>
<span class="visible-if-sending">{% trans 'Sending...' %}</span>
<span class="visible-if-successful">{% trans 'Saved successfully' %}</span>
Expand Down
62 changes: 0 additions & 62 deletions evap/evaluation/templates/sortable_form_js.html

This file was deleted.

15 changes: 14 additions & 1 deletion evap/evaluation/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,20 @@
from model_bakery import baker

from evap.evaluation.models import Evaluation, Question, QuestionType, UserProfile
from evap.evaluation.tests.tools import WebTestWith200Check, create_evaluation_with_responsible_and_editor
from evap.evaluation.tests.tools import (
WebTestWith200Check,
create_evaluation_with_responsible_and_editor,
store_ts_test_asset,
)


class RenderJsTranslationCatalog(WebTest):
url = reverse("javascript-catalog")

def render_pages(self):
# Not using render_pages decorator to manually create a single (special) javascript file
content = self.app.get(self.url).content
store_ts_test_asset("catalog.js", content)


@override_settings(PASSWORD_HASHERS=["django.contrib.auth.hashers.MD5PasswordHasher"])
Expand Down
21 changes: 13 additions & 8 deletions evap/evaluation/tests/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ def let_user_vote_for_evaluation(user, evaluation, create_answers=False):
RatingAnswerCounter.objects.bulk_update(rac_by_contribution_question.values(), ["count"])


def store_ts_test_asset(relative_path: str, content) -> None:
absolute_path = os.path.join(settings.STATICFILES_DIRS[0], "ts", "rendered", relative_path)

os.makedirs(os.path.dirname(absolute_path), exist_ok=True)

with open(absolute_path, "wb") as file:
file.write(content)


def render_pages(test_item):
"""Decorator which annotates test methods which render pages.
The containing class is expected to include a `url` attribute which matches a valid path.
Expand All @@ -94,19 +103,15 @@ def render_pages(test_item):
The value is a byte string of the page content."""

@functools.wraps(test_item)
def decorator(self):
def decorator(self) -> None:
pages = test_item(self)

static_directory = settings.STATICFILES_DIRS[0]

url = getattr(self, "render_pages_url", self.url)
# Remove the leading slash from the url to prevent that an absolute path is created
directory = os.path.join(static_directory, "ts", "rendered", url[1:])
os.makedirs(directory, exist_ok=True)

for name, content in pages.items():
with open(os.path.join(directory, f"{name}.html"), "wb") as html_file:
html_file.write(content)
# Remove the leading slash from the url to prevent that an absolute path is created
path = os.path.join(url[1:], f"{name}.html")
store_ts_test_asset(path, content)

return decorator

Expand Down
30 changes: 30 additions & 0 deletions evap/locale/de/LC_MESSAGES/djangojs.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# EvaP translation
# This file is distributed under the same license as the EvaP project.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: EvaP\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-10-30 17:26+0100\n"
"PO-Revision-Date: 2023-10-30 17:26+0100\n"
"Last-Translator: Johannes Wolf <[email protected]>\n"
"Language-Team: Johannes Wolf (janno42)\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.3.2\n"

#: evap/static/js/notebook.js:30 evap/static/ts/src/notebook.ts:39
msgid "The server is not responding."
msgstr ""

#: evap/static/js/sortable_form.js:19
msgid "Delete"
msgstr ""

#: evap/static/js/sortable_form.js:20
msgid "add another"
msgstr ""
4 changes: 3 additions & 1 deletion evap/staff/templates/staff_course_type_index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{% extends 'staff_base.html' %}

{% load static %}

{% block breadcrumb %}
{{ block.super }}
<li class="breadcrumb-item">{% trans 'Course types' %}</li>
Expand Down Expand Up @@ -71,7 +73,7 @@
{% endblock %}

{% block additional_javascript %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>

<script type="text/javascript">
rowChanged = function(row) {
Expand Down
4 changes: 3 additions & 1 deletion evap/staff/templates/staff_degree_index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{% extends 'staff_base.html' %}

{% load static %}

{% block breadcrumb %}
{{ block.super }}
<li class="breadcrumb-item">{% trans 'Degrees' %}</li>
Expand Down Expand Up @@ -67,7 +69,7 @@
{% endblock %}

{% block additional_javascript %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>

<script type="text/javascript">
rowChanged = function(row) {
Expand Down
4 changes: 3 additions & 1 deletion evap/staff/templates/staff_faq_index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{% extends 'staff_base.html' %}

{% load static %}

{% block breadcrumb %}
{{ block.super }}
<li class="breadcrumb-item">{% trans 'FAQ Sections' %}</li>
Expand Down Expand Up @@ -57,7 +59,7 @@
{% endblock %}

{% block additional_javascript %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>

<script type="text/javascript">
rowChanged = function(row) {
Expand Down
4 changes: 3 additions & 1 deletion evap/staff/templates/staff_faq_section.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{% extends 'staff_base.html' %}

{% load static %}

{% block breadcrumb %}
{{ block.super }}
<li class="breadcrumb-item"><a href="{% url 'staff:faq_index' %}">{% trans 'FAQ Sections' %}</a></li>
Expand Down Expand Up @@ -57,7 +59,7 @@
{% endblock %}

{% block additional_javascript %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>

<script type="text/javascript">
rowChanged = function(row) {
Expand Down
4 changes: 3 additions & 1 deletion evap/staff/templates/staff_questionnaire_form.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{% extends 'staff_questionnaire_base.html' %}

{% load static %}

{% block content %}
{{ block.super }}
{% if not editable %}
Expand Down Expand Up @@ -79,7 +81,7 @@ <h5 class="card-title">{% trans 'Questions' %}</h5>

{% block additional_javascript %}
{% if editable %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>
<script type="text/javascript">
rowChanged = function(row) {
nameDe = $(row.find('textarea[id$=-text_de]')).val();
Expand Down
4 changes: 2 additions & 2 deletions evap/staff/templates/staff_semester_export.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends 'staff_semester_base.html' %}

{% load evaluation_filters %}
{% load evaluation_filters static %}

{% block breadcrumb %}
{{ block.super }}
Expand Down Expand Up @@ -72,7 +72,7 @@ <h3>{% trans 'Export' %} {{ semester.name }}</h3>
{% endblock %}

{% block additional_javascript %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>

<script type="text/javascript">
rowChanged = function(row) {
Expand Down
2 changes: 1 addition & 1 deletion evap/staff/templates/staff_text_answer_warnings.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
{% endblock %}

{% block additional_javascript %}
{% include 'sortable_form_js.html' %}
<script src="{% static 'js/sortable_form.js' %}"></script>

{{ text_answer_warnings|text_answer_warning_trigger_strings|json_script:'text-answer-warnings' }}

Expand Down
1 change: 1 addition & 0 deletions evap/static/js/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ignore the typescript output, but still track the libraries
*.js
!*.min.js
!sortable_form.js
60 changes: 60 additions & 0 deletions evap/static/js/sortable_form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
function makeFormSortable(tableId, prefix, rowChanged, rowAdded, tolerance, removeAsButton, usesTemplate) {

function applyOrdering() {
$(document).find('tr').each(function(i) {
if (rowChanged($(this))) {
$(this).find('input[id$=-order]').val(i);
}
else {
// if the row is empty (has no text in the input fields) set the order to -1 (default),
// so that the one extra row doesn't change its initial value
$(this).find('input[id$=-order]').val(-1);
}
});
}

$('#' + tableId + ' tbody tr').formset({
prefix: prefix,
deleteCssClass: removeAsButton ? 'btn btn-danger btn-sm' : 'delete-row',
deleteText: removeAsButton ? '<span class="fas fa-trash"></span>' : gettext('Delete'),
addText: gettext('add another'),
added: function(row) {
row.find('input[id$=-order]').val(row.parent().children().length);

// We have to empty the formset, otherwise sometimes old contents from
// invalid forms are copied (#644).
// Checkboxes with 'data-keep' need to stay checked.
row.find("input:checkbox:not([data-keep]),:radio").removeAttr("checked");

row.find("input:text,textarea").val("");

row.find("select").each(function(){
$(this).find('option:selected').removeAttr("selected");
$(this).find('option').first().attr("selected", "selected");
});

//Check the first item in every button group
row.find(".btn-group").each(function() {
var inputs = $(this).find("input");
$(inputs[0]).prop("checked", true);
});

//Remove all error messages
row.find(".error-label").remove();

rowAdded(row);
},
formTemplate: (usesTemplate ? ".form-template" : null)
});

new Sortable($('#' + tableId + " tbody").get(0), {
handle: ".fa-up-down",
draggable: ".sortable",
scrollSensitivity: 70
});

$('form').submit(function() {
applyOrdering();
return true;
});
}
3 changes: 2 additions & 1 deletion evap/static/ts/src/notebook.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "./translation.js";
import { unwrap, assert, selectOrError } from "./utils.js";

const NOTEBOOK_LOCALSTORAGE_KEY = "evap_notebook_open";
Expand Down Expand Up @@ -35,7 +36,7 @@ class NotebookFormLogic {
.catch(() => {
this.notebook.setAttribute("data-state", "ready");
submitter.disabled = false;
alert(submitter.dataset.errormessage);
alert(window.gettext("The server is not responding."));
});
};

Expand Down
Loading