djsmith
djsmith

Reputation: 3087

How to fall back to multiple languages in Django at runtime?

I am building a Django app that uses Django's translation features to provide localization to multiple languages. But I am also using Django's translation features to translate certain terminology into different industries based on the currently logged in user's settings.

For example, for an English speaking user working in the learning assessment industry, I want the following behavior:

For a given request to a page:

  1. Look up the user's natural language (e.g., German)
  2. Look up the user's industry (e.g., learning assessment)
  3. Activate the German/Learning Assessment language (e.g., translation.activate("learning-assessment-de")

The "learning-assessment-de" .po file will only translate a subset of all the strings in the project, because it's only there to translate certain industry-specific terminology.

This is the question:

When a string is missing, I want Django to fall back to German (determined in step #1 above) rather than English (the default language in my settings.py).

My default English/German .po files will assume a certain industry.

Is this possible?

Upvotes: 9

Views: 1233

Answers (1)

HankMoody
HankMoody

Reputation: 3174

I think it's possible and one of the fastest ways to do this (even if to test if it works) would be to monkey-patch Django translation module to add fallback language support like this (not tested):

from django.utils.translation import trans_real
... # Import other things


# Added `fallback_language` parameter
def do_translate(message, translation_function, fallback_language=None):
    """
    Translates 'message' using the given 'translation_function' name -- which
    will be either gettext or ugettext. It uses the current thread to find the
    translation object to use. If no current translation is activated, the
    message will be run through the default translation object.
    """
    global _default

    # str() is allowing a bytestring message to remain bytestring on Python 2
    eol_message = message.replace(str('\r\n'), str('\n')).replace(str('\r'), str('\n'))
    t = getattr(_active, "value", None)
    if t is not None:
        result = getattr(t, translation_function)(eol_message)
    else:

        # Use other language as fallback.
        if fallback_language is not None:
            fallback = translation(fallback_language)
            result = getattr(_default, translation_function)(eol_message)

        else:
            if _default is None:
                from django.conf import settings
                _default = translation(settings.LANGUAGE_CODE)
            result = getattr(_default, translation_function)(eol_message)
    if isinstance(message, SafeData):
        return mark_safe(result)
    return result

# Added `fallback_language` parameter
def do_ntranslate(singular, plural, number, translation_function, fallback_language=None):
    global _default

    t = getattr(_active, "value", None)
    if t is not None:
        return getattr(t, translation_function)(singular, plural, number)

    # Use other language as fallback.
    if fallback_language is not None:
       fallback = translation(fallback_language)
       return getattr(fallback, translation_function)(singular, plural, number)

    if _default is None:
        from django.conf import settings
        _default = translation(settings.LANGUAGE_CODE)
    return getattr(_default, translation_function)(singular, plural, number)


# Override Django functions with custom ones.
trans_real.do_translate = do_translate
trans_real.do_ntranslate = do_ntranslate

The two above functions are taken from the django.utils.translation.trans_real module. Just added few lines to these functions. You will also need to modify the other functions (e.g. gettext, ngettext, pgettext) to accept the fallback_language parameter and pass it to the two above ones. Please try if this code works.

Note, that monkey-patching is project-wide - it affects Your whole application and third-party applications too. Alternatively You may take the source of the django.utils.translation.trans_real module as a base to create custom translation functions that will be used only in few places in your application.

Upvotes: 1

Related Questions