6

I've a couple of Django projects using translations and everything works fine except Javascript error messages on forms are not translating.

For example, on my Login form, if I simply press enter I will get the JS error message "Please fill in this field" in English, whether I've selected English, French, German or any other language. This is not my JS error message and if I run manage.py makemessages -d djangojs, then this message doesn't show up to translate so I don't think I need to correct through that process.

Can anyone advise me how to ensure the user is getting JavaScript error messages in their language. Thanks

HenryM
  • 5,557
  • 7
  • 49
  • 105

3 Answers3

2

The docs say you are supposed to use django-admin makemessages -d djangojs -l de, and not python manage.py ..., also make sure you run django-admin compilemessages afterwards.

If that still doesn't work, you can try using the trans tag, then manually add the error message using event listeners on your templates.

At the top of the page:

{% load trans %}

For pure javascript:

var inputs = document.querySelectorAll("input");

inputs.forEach(function(input) {
  if (input.hasAttribute("required")) {
    input.oninvalid = function() {
      this.setCustomValidity("{% trans 'Please fill in this field' %}");
    }
  });
});

jQuery:

$("input[required]").on("invalid", function() {
    this.setCustomValidity("{% trans 'Please fill in this field' %}");
});

If this solution doesn't work for your specific use case, the docs go into detail about various alternatives.

Lord Elrond
  • 13,430
  • 7
  • 40
  • 80
0

Django provides a specific solution to handle this:

https://docs.djangoproject.com/en/2.2/topics/i18n/translation/#module-django.views.i18n

but when the number of messages used in js code which need translation is limited, as commonly happens, I prefer to use a much simpler solution.

First, I create a "js message catalog" in the "templates" folder; it just contains a list of global string literals.

Since the template engine isn't restricted to HTML, and can handle any file type, you can {% load i18n %} at the beginning of the js file, and make use of 'trans' and other template tags as required to mark translatable string values; these values will be detected by "makemessages" as expected.

file "/myapp/templates/message_catalog.js"

{% load i18n %}

MESSAGE_HELLO = "{% trans 'hello' %}";
MESSAGE_GOODBYE = "{% trans 'goodbye' %}";
...

Then, just remember to include it in the main template, so the message catalog will be accessible from js code:

file "/myapp/templates/base.html"

...
    <script>
        {% include 'message_catalog.js' %}
    </script>

</body>
</html>

The 'real' js code can live in static as usual, and still has access to translated messages:

file "/myapp/static/frontend.js"

function hello() {
    alert(MESSAGE_HELLO);
}

function goodbye() {
    alert(MESSAGE_GOODBYE);
}
Mario Orlandi
  • 5,629
  • 26
  • 29
  • Issue is, the Javascript messages do not show in djangojs.po because they are part of standard JS and not the javascript I've written – HenryM Sep 30 '19 at 16:44
  • mmhhh, I see .. is it HTM5 form field validation provided by the browser ? Supplying your own messages could be tricky; I would rather add the "novalidate" attribute to the form to disable it altogether (
    ), then either apply validation server side or with your own javascript
    – Mario Orlandi Sep 30 '19 at 17:32
  • It is, but surely this is in multiple languages and should be picked up via the language setting - how do I check which language the browser thinks is being used – HenryM Sep 30 '19 at 17:40
  • Just guessing ... I do believe that the browser suggests a "preferred language" in the request headers, but then Django can decide to use another one instead, based on it's own settings, or on the user's choice kept in the cookies and previously selected on your web page. Not sure whether you could go the other way around, that is: suggest TO THE BROWSER the language you (the server) believe should be in use. I would check this: https://docs.djangoproject.com/en/2.2/topics/i18n/translation/#how-django-discovers-language-preference – Mario Orlandi Sep 30 '19 at 17:59
  • I posted another answer, mainly to share this discussion and to have some formatting options available ... but I do understand it's not a solution to the problem you expressed ;) Thank you for discussion ;) – Mario Orlandi Oct 01 '19 at 06:54
0

Here, I assume we're talking about form field validation provided by the browser.

You can specify both a default language for the entire HTML page, and a specific language for a section, and in principle the browser should make good use of it.

However, up to now, browser support on this area is still poor and unreliable.

I tried this with Chrome and Safari:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>title</title>
    </head>
    <body>

        <p>form with default lang (en)</p>
        <form>
            <input type="text" required>
            <br />
            <input type="submit">Save
        </form>

        <p>form with specific lang (it)</p>
        <form lang="it">
            <input type="text" required>
            <br />
            <input type="submit">Salva
        </form>

    </body>
</html>

and this is the disappointing result:

enter image description here

There are a few constraint Validation DOM Methods, like checkValidity(), setCustomValidity() and reportValidity() which could help in controlling the validation message, but they're all referred to be poorly supported, too.

Personally, I prefer to disable browser validation altogether, and run my own instead, either server-side or client-side, to have better control of the user interaction.

<form ... novalidate>
    ...
Mario Orlandi
  • 5,629
  • 26
  • 29