fix(admin): apostrophe-in-translation broke /admin/stations Alpine bindings

Two error messages on /admin/stations rendered Italian translations
that contain an apostrophe inside a single-quoted JS literal:

  alert(result.detail || '{{ _("Errore nell\'eliminazione") }}');

Jinja outputs the apostrophe verbatim, so the JS string closed
prematurely:

  alert(result.detail || 'Errore nell'eliminazione');

That syntax error blew up the entire <script> block, which means
stationManagement() was never defined and EVERY Alpine binding on the
page failed silently. Symptom: clicking "Nuova Stazione" did nothing,
DevTools showed "Alpine Expression Error: openCreateModal is not
defined".

Fix: swap outer JS quotes to double quotes and reword the IT string so
the apostrophe disappears anyway ("Errore nella eliminazione",
"Errore nella assegnazione"). Same for the assignment-error path.

Regression guard: src/frontend/flask_app/tests/test_template_js_syntax.py
renders /admin/stations and /admin/users with the IT locale forced,
extracts every inline <script>, and runs `node --check` on each. The
test is skipped if `node` is not on PATH so CI without Node still
passes. Verified the test catches the original bug (revert + run +
fail) before re-applying the fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 12:32:32 +02:00
parent 742cc1fb58
commit 6e284b0c0c
2 changed files with 129 additions and 2 deletions
@@ -477,7 +477,7 @@ function stationManagement(initialStations, initialRecipes) {
});
if (!resp.ok) {
const result = await resp.json().catch(() => ({}));
alert(result.detail || '{{ _("Errore nell\'eliminazione") }}');
alert(result.detail || "{{ _('Errore nella eliminazione') }}");
return;
}
this.stations = this.stations.filter(s => s.id !== this.deleteTarget.id);
@@ -528,7 +528,7 @@ function stationManagement(initialStations, initialRecipes) {
});
const result = await resp.json();
if (!resp.ok) {
this.errorMsg = result.detail || '{{ _("Errore nell\'assegnazione") }}';
this.errorMsg = result.detail || "{{ _('Errore nella assegnazione') }}";
return;
}
const recipe = this.allRecipes.find(r => r.id === parseInt(this.recipeToAdd, 10));