Django Translator

Django Translator

Translate Your App Using a Great Alternative To Django Rosetta

Every day, we work hard to bring our clients' projects into a life using Django. Besides other great features, we love this Python framework because of its huge list of third party packages.

As a team working for years with an open source software, we feel responsible and don't want just to pull packages out of the community. So, we strive to devote some of our coffee-gained energy into a Django community projects on a regular basis. One of these projects relates to a development of multilingual web applications.

Since most of our large projects need internationalization, we used Django Rosetta for a couple of years. It is a very popular and powerful Django package, but as a time went by, we came across some of its limits:

  • It has no option to ignore fuzzy translations (translation suggestions).
  • It doesn’t allow you to use advanced filters, or create categories.
  • It can’t be fully controlled from a Django admin.
  • It doesn’t create backups of translations.

Actually, it was the reason why we decided to develop our own solution. It is called Django Translation Manager and removes above-mentioned constraints.

Moreover, in comparison to Django Rosetta, all translations are safely stored within your own database.

So, let's dive into how Translation Manager works, and how to seamlessly install it into your Django project.

1. Label translation strings at a very beginning of your project

Translation Manager is based on Django's translation i18n basics and extends its capabilities. Django translations are well documented in the official Django documentation, so we will keep it short here.

To make your projects translatable, you must include hooks within your Python code as well as within templates. We strongly advocate adding these hooks to your source code at the very beginning of your project, even before you install Translation Manager. Believe us, it’s a nightmare to refactor all strings at a final stage of project development.

These hooks are well known as translation strings. They simply tell Django that this part of the text should be translated into the end user’s language at a time of loading of your website.

Designation of translation strings within your Python code can be done using Django's ugettext() or ugettext_lazy() module.


from django.utils.translation import ugettext_lazy
uggettext_lazy(“your-translation-string”)

Although Django documentation discourages this practice, it’s a common convention to import this as a shorter alias, _, to save typing.


from django.utils.translation import ugettext_lazy as _
_(“your-translation-string”)

Translations in Django templates use two template tags - {% trans %} and {% blocktrans %}. To be able to access these tags, you must put {% load i18n %} toward the top of your template.


{% load i18n %}
{% trans “your-translation-string” %}

or


{% load i18n %}
{% blocktrans %}your-translation-string{% endblocktrans %}

2. Install Translation Manager

  • Use pip to get the package:

pip install django-translation-manager
  • Add 'translation_manager' into INSTALLED_APPS in your project’s settings.py:

INSTALLED_APPS = (
    ...
    'translation_manager',
)
  • Add desired languages to your project’s settings.py:

LANGUAGES = (
    ('cs', _('czech')),
    ('en', _('english')),
)
  • Following our above-mentioned example with LANGUAGES variable, create following directories in a root of your project:

locale/cs/LC_messages
locale/en/LC_messages
  • Synchronize your database with python manage.py syncdb or python manage.py migrate depending on your Django version.

3. Create a message file containing your translations from Django’s admin interface

Translation Manager uses Django's utilities to extract translation strings into a message file. The message file is a plain-text file, representing a single language, that contains all available translation strings together with their counterparts in that language. The message file has a .po file extension.

Django’s default translation uses the following command to create or update a message file:


python manage.py makemessages

This command runs a script that goes through your source tree and pulls out all strings marked for a translation (from step 1). It creates (or updates) *.po message files in corresponding ‘LC_messages’ directories (step 2).

This step is where our Translation Manager takes control over the default Django translations or Django Rosetta. Since Translation Manager is being installed into your project as a separate app, you can easily access your translation strings using a standard Django admin interface.

Therefore, it’s not further necessary to run the makemessages command from a command line (although you are still free to do it yourself). Translation Manager allows you to click an “Update the list of translations” button located at a top right section of the Django admin to call the command automatically.

Once you do that, you will see your translation strings right in the Django admin. Besides generating or updating *.po message files, Translation Manager also stores their content into the database.

4. Translate all translation strings

In order to make the process as simple as possible, Translation Manager allows you to edit all translations right from a list of translation strings in Django’s admin.

You are also free to filter your translation strings. However, to get the most out of this feature, we strongly recommend you to use a strict style when creating the translation strings.

It is simpler than it sounds. You just sort out translation strings into several categories according to their purpose and location.

As usually, an example is better than thousand words - use 'front-' prefix for your frontend strings, 'admin-' prefix for purely backend strings, and 'email-' prefix for all email template strings. This part is connected to TRANSLATION_QUERYSET_FORCE_FILTERS settings variable specified in a Step 6, so keep on reading.

As mentioned earlier, Translation Manager creates its own database structure within your project where all translations are stored. It allows you to track all changes of translations made by other users, as well as to keep backups of all previous versions.

Translation Manager in Django admin

Translation Manager in Django admin

5. Publish your translations

When your *.po message files are created and all translation strings are translated, it’s time to show off your new multilingual copywriting to the world. In order to do that, you need to compile *.po message files into a more efficient form that can be used by ugettext() or lazy_ugettext() modules.

It can be done by running Django’s default translation command in your command line:


python manage.py compilemessages

A situation is the same as with the makemessages command from a Step 3. Translation Manager will call the command when you hit a “Publish translations” button from Django’s admin interface. As a result, compiled *.mo messages are created in ‘LC_messages’ directories (coming from Step 2).

6. Restart your web server

In order to see your published translations live, you must restart your web server.

Of course, you can do it manually. But, as you can expect, Translation Manager also transmits a signal telling Django that your message files were compiled and translations was published. You can easily retrieve the signal to automate the restarting process:


from translation_manager.signals import post_save as translation_post_save
translation_post_save.connect(restart_server, sender=None)

Your restart_server function for gunicorn can look as follows:


def restart_server(sender, **kwargs):
    request = kwargs.pop('request', {"META": {}})
    gunicorn_served = bool(re.match(r"gunicorn", request.META.get("SERVER_SOFTWARE", u"")))
    if gunicorn_served:
        management.call_command('hup', verbosity=0, interactive=False)

7. Customize Translation Manager to your needs

This step is fully optional. You can customize the app so it perfectly fits your requirements by adding following variables from Translation Manager's defaults.py to your settings.py:

LOCALE_PATHS (list)

A list of paths to your ‘locale’ directories. By default, a ‘locale’ directory in your project’s root is considered.

TRANSLATIONS_BASE_DIR (string)

A string specifying a directory within your project source, from where Translation Manager searches for translation strings. By default, you project’s root directory is considered.

TRANSLATIONS_IGNORED_PATHS (list)

A list of paths where Translation Manager ignores occurrence of message *.po files, e.g. [‘env’, ‘media’].

TRANSLATIONS_MAKE_BACKUPS (boolean)

A boolean value specifying whether automatic backups are made when the database is updated with new translations.

TRANSLATIONS_CLEAN_PO_AFTER_BACKUP (boolean)

A boolean value specifying whether message *.po files are deleted after creation of backups.

Following settings affect a Django admin interface:

TRANSLATIONS_QUERYSET_FORCE_FILTERS (list)

A list of translation strings prefixes. If your translation strings contain these prefixes, you can filter them right in the Django admin. Go back to Step 4 to read more.


TRANSLATIONS_QUERYSET_FORCE_FILTERS = ['admin-', 'front-', 'email-']
TRANSLATIONS_HINT_LANGUAGE (string)

A string value specifying a default language for a help text. When you translate your message files, the help text in a given language (if provided) is displayed right beside your translation string for your easy reference.

TRANSLATIONS_ADMIN_EXCLUDE_FIELDS (list)

A list of strings specifying fields that are excluded from Django’s admin interface (columns).

TRANSLATIONS_ADMIN_FIELDS (list)

As opposite to to a previous variable, this list of strings specifies fields that are included in Django’s admin interface as columns.

TRANSLATIONS_CUSTOM_FILTERS (list)

You are allowed to define one extra custom filter. It should be a list, where a first value is a string specifying a filter title. A second value should be a list containing a tuples of regular expressions matching your filter, and a displayed titles of used filters.


TRANSLATIONS_CUSTOM_FILTER = [
    gettext_noop(‘admin-translation_manager-filter-title’), [
        (‘^admin-',gettext_noop(‘admin-translation_manager-filter-admin’)), 
        (‘^front-',gettext_noop(‘admin-translation_manager-filter-front’)),
        (‘^email-',gettext_noop(‘admin-translation_manager-filter-email’))
    ]
]

As we wrote at the beginning, Django Rosetta is very popular Django package and we really appreciate an effort of developers behind it.

On the other side, it has several serious limitations that don’t fit our requirements. If it is your case too, give Translation Manager a try and let us know about your experience.

If you have any comments or thoughts, we would love to hear any feedback.

Your COEX team.


Bottom Line:

The first version of Translation Manager was launched at the end of 2014. The project is licensed under Mozilla Public License 2.0 which means it can be used for free as well as for business projects. Translation Manager is compatible with Django 1.4 - 1.7 under a 0.2.7 version code. There is also a 0.3.0+ version, which is under constant development, and support Django 1.8+.

Source code can be found at https://github.com/COEXCZ/django-translation-manager