Search code examples
djangodjango-i18n

Django uggetext as __ instead of _ breaks makemessages


I just came across a weird bug (?) where I initially had

from django.utils.translation import ugettext as _

Which I changed for

from django.utils.translation import ugettext as __

But, surprisingly, running ./manage.py makemessages --all after doing that breaks all translations, they basically get all commented in my .po files, as if they weren't recognized as being translations anymore.

Going back to _ and running makemessages fixes it. I don't quite follow why the name of the variable matters, and I wonder how I should name my ugettext and ugettext_lazy when I need both, for consistency.

Django 1.8, with python 2.7.14


Solution

  • That's because of the internals of the gettext utility and more specifically of the xgettext command.

    In short, in order to mark strings as translatable you must wrap them in specific keywords (i.e translate("hello world"), translate here is the keyword). The xgettext program works for many programming languages. Each language has its own predefined keywords (press Ctrl + f and search for --keyword).

    In Python, these keywords are (note the _ at the end):

    For Python: gettext, ugettext, dgettext:2, ngettext:1,2, ungettext:1,2, dngettext:2,3, _

    xgettext command has several options which alter it's behavior. One of these, is --keyword option. When you invoke the xgettext command with the --keyword option, then all strings in a python file will be considered translatable if they are wrapped in one of the predefined keywords or the --keyword option(s) you gave. If, for example you run xgettext --keyword=jimmy_hendrix then all strings like jimmy_hendrix("hello world") will be included in your .po file.

    But, you will never run this command, in Django, explicitly. You use the makemessages command. Looking at the source of makemessages command, you can see that Django provides additional --keywords for marking strings for translation. In fact, these keywords are the same as Django's additional functions for translation.

    After all these, I think it's clear now that aliasing __ or ___ will not work since it's not in the list of Django's xgettext command invocation, neither in the predefined keywords of xgettext command.

    You may look at an outdated, but still valid answer.

    Also, an example of xgettext on MDN, using PHP.