Search code examples
djangodjango-1.7django-multilingual

Django translation discovery looking at site-packages first


Having trouble getting any of my translation files after compilemessages to take effect.

Digging into the code I came to:

django.utils.translation.trans_real.check_for_language

def check_for_language(lang_code):
    # First, a quick check to make sure lang_code is well-formed (#21458)
    if not language_code_re.search(lang_code):
        return False
    for path in all_locale_paths():
        if gettext_module.find('django', path, [to_locale(lang_code)]) is not None:
            return True
    return False

Which makes use of:

django.utils.translation.trans_real.all_locale_paths

def all_locale_paths():
    from django.conf import settings
    globalpath = os.path.join(
        os.path.dirname(upath(sys.modules[settings.__module__].__file__)), 'locale')
    return [globalpath] + list(settings.LOCALE_PATHS)

Which returns:

[
  u'/data/.venv/mysite/local/lib/python2.7/site-packages/django/conf/locale',
  '/data/www/locale/'
]

This is such core code, tested probably a million times, I'm sure I'm configuring wrong, but I can't really see any way that my LOCALE_PATHS will ever take precedence?

/data/www/locale/ content

/data/www/locale/
|-- en-us
|   `-- LC_MESSAGES
|       |-- django.mo
|       `-- django.po
|-- zh-hans
|   `-- LC_MESSAGES
|       |-- django.mo
|       `-- django.po
`-- zh-hant
    `-- LC_MESSAGES
        |-- django.mo
        `-- django.po

settings.py

LANGUAGES_DICT = {
    'en-us': _('English'),
    'zh-hant': _('Traditional Chinese'),
    'zh-hans': _('Simplified Chinese'),
}
LANGUAGES = LANGUAGES_DICT.items()

BASE_DIR = os.path.dirname(os.path.dirname(__file__))
path = lambda *a: os.path.join(BASE_DIR, *a)
LOCALE_PATHS = (
    path(u'locale'),
)
# Outputs: (u'/data/www/locale',)

Solution

  • The language directories in /data/www/locale/ should be separated by underscores instead of hyphens. The naming can be compared against Django's official repo.

    In case of zh_Hans and zh_Hant it also seems appropriate to uppercase only the first letter of the 4-characters behind the hyphen (that said, testing it it also worked with lower-case names like zh_hans).

    /data/www/locale/
    |-- en_US
    |-- zh_Hans
    `-- zh_Hant
    

    Against my previous comment these underscores should only be in the directory names, they need to remain separated by hyphens in settings.py.

    To initially create the directories with this name (no need to recreate them if they already exist, renaming should be enough):

    $ django-admin.py makemessages -l zh_Hant
    $ django-admin.py makemessages -l zh_Hans
    

    After compiling the messages and restarting runserver (it can't detect file changes outside the project root) the translations should show, at least it worked for me while testing it in Django Admin with translating verbose_name_plural of a test model.

    One thing I've noticed, the directory /data/www/locale/ needs to be on Python path in order for Django to pick the translations up.