11

I am trying to add a Chinese language to my application written in Django and I have a really hard time with that. I have spent half a day trying different approaches, no success.

My application supports few languages, this is part of settings.py file:

TIME_ZONE = 'Europe/Dublin'
LANGUAGE_CODE = 'en'

LOCALES = (
    #English
    ('en', u'English'),

    #Norwegian
    ('no', u'Norsk'),

    #Finish
    ('fi', u'Suomi'),

    #Simplified Chinese
    ('zh-CN', u'简体中文'),

    #Traditional Chinese
    ('zh-TW', u'繁體中文'),

    #Japanese
    ('ja', u'日本語'),
)

At the moment all (but Chinese) languages work perfectly. This is a content of locale directory:

$ ls locale/
en
fi
ja
no
zh_CN
zh_TW

In every directory I have LC_MESSAGES directory with *.mo and *.po files. *.po files are created by script written in Python, which converts *.ODS to a text file. *.mo files are created by python manage.py compilemessages command.

Language can be selected by user from the proper form in "Preferences" section in my application.

Django does not load Chinese translation. That is the problem. Both simplified and traditional does not work. I have tried different variations of language and locale codes in settings.py and in locale directory: zh-CN, zh-cn, zh_CN, zh_cn. No success.

Perhaps I made a simple mistake? I have added Polish language just for test and everything went fine. Basically I did the same. I have added ('pl', u'Polish') tuple to the settings.py and "locale/pl" with *.po and *.mo and LC_MESSAGES directory...

Do you know what might be wrong?

Makoto
  • 104,088
  • 27
  • 192
  • 230
Pavulon
  • 111
  • 1
  • 1
  • 7
  • Did you finally manage to find a solution to this? I am having the same problem with chinese - using only one dialect and defining them as ('zh-cn', gettext('Chinese')) in the settings file and naming the folder zh_cn in the locale dir – FoF Feb 20 '12 at 11:47
  • I finally managed to solve it, locally the dir in locale had to be named zh_cn but in the server it only worked when the dir in locale was named as zh-CN. Don't really know why... – FoF Feb 20 '12 at 12:52

5 Answers5

18

You will need to use lower case for your locale language codes for it to work properly. i.e. use

LANGUAGES = (
    ('zh-cn', u'简体中文'), # instead of 'zh-CN'
    ('zh-tw', u'繁體中文'), # instead of 'zh-TW'
)

See the language codes specified in https://code.djangoproject.com/browser/django/trunk/django/conf/global_settings.py. You will see that it uses zh-tw instead of zh-TW.

Finally, the language directories storing the *.po and *.mo files in your locales folder needs to be named zh_CN and zh_TW respectively for the translations to work properly.

Derek Kwok
  • 12,768
  • 6
  • 38
  • 58
  • I have followed you advice and translation still does not work. But thank you for clarifying settings convention. Problem might be somewhere else in the application. I think it is even more probable now. I will keep investigating. – Pavulon Oct 12 '11 at 09:48
  • I just want to confirm quickly with you: in your settings.py file, do you have `LOCALE_PATHS` variable set? Also, do you have `'django.middleware.locale.LocaleMiddleware'` specified in `MIDDLEWARE_CLASSES` variable? – Derek Kwok Oct 12 '11 at 16:01
  • Derek, thank you for you input here. Yes, I have `django.middleware.locale.LocaleMiddleware` in the settings.py, but I do not have `LOCALE_PATHS` defined. I am working with Django 1.3 and as far as I understand Django looks for translation in **locale** directory inside the project. I think this feature is deprecated and will be removed in next releases of Django codebase, but it seems to work at the moment, because other languages works really well. – Pavulon Oct 17 '11 at 09:24
  • The really difference I can see now is the fact that Chinese requires two dialects. All other languages supported by the application (Japanese, Finish, Norwegian and Polish which I tested only) have one dialect only... – Pavulon Oct 17 '11 at 09:27
  • 3
    This did the trick for me! I have "zh-cn" in my settings.py, but I have to run "makemessages -l zh_CN". Thank you so much! This caused major frustration. – mbrochh Mar 13 '12 at 03:20
  • Actually that Github link now mentions "zh-hans" instead of "zh-cn" – littlegreen Feb 02 '15 at 20:09
  • Just a heads up. It's now `zh-hans` but not `zh-cn` anymore. – John Wu Mar 04 '16 at 16:31
  • 2
    For simplified Chinese(`zh-cn`), it's `zh-hans` now. For `zh-hant`(Traditional Chinese), it's `zh-hant` now. `(Django 1.9 new update)` – Alston Jul 27 '16 at 14:09
12

For Django 1.7 and up, you'll need to do the following:

zh-hans in your config, and make sure that your directory is named zh_Hans.

And for traditional Chinese:

zh-hant in your config, and your directory should be named zh_Hant.

Here is an example of how the auth contributor package lays out its translations in the locale directory: https://github.com/django/django/tree/master/django/contrib/auth/locale

Basically, for our Chinese language codes, the - is replaced with a _, and the first letter of the second work is capitalized.

Source code for this logic is here: https://github.com/django/django/blob/7a42cfcfdc94c1e7cd653f3140b9eb30492bae4f/django/utils/translation/init.py#L272-L285

and just to be thorough, here is the method:

def to_locale(language, to_lower=False):
    """
    Turns a language name (en-us) into a locale name (en_US). If 'to_lower' is
    True, the last component is lower-cased (en_us).
    """
    p = language.find('-')
    if p >= 0:
        if to_lower:
            return language[:p].lower() + '_' + language[p + 1:].lower()
        else:
            # Get correct locale for sr-latn
            if len(language[p + 1:]) > 2:
                return language[:p].lower() + '_' + language[p + 1].upper() + language[p + 2:].lower()
            return language[:p].lower() + '_' + language[p + 1:].upper()
    else:
return language.lower()

Note that en-us is turned into en_US, based on the source code above, because us is 2 characters or less.

modulitos
  • 14,737
  • 16
  • 67
  • 110
  • 1
    A useful link is https://docs.djangoproject.com/en/1.10/topics/i18n/translation/ , especially the [How Django discovers translations](https://docs.djangoproject.com/en/1.10/topics/i18n/translation/#how-django-discovers-translations) part. – LShi Dec 09 '16 at 05:09
  • any reason why they did it this way? Seems like browsers put zh-tw header rather then zh-hans for users from China (see answer: https://stackoverflow.com/questions/69709824/what-is-the-typical-chinese-language-code-for-the-accept-language-header ) – tikej Nov 05 '21 at 17:34
2

I had the same problem [Django-1.6.1] and solved it by renaming the locale directories for Chinese from zh-cn (or zh_cn) to zh_CN (underscore and uppercase CN).

Strangely enough Django requires a "zh-cn" as LANGUAGE_CODE or url with an i18n_pattern respectively.

Non-documented goodness btw.

Hope that helps.

1

In .po file, add zh-cn or zh-tw in "Language: \n", which becomes "Language: zh-en\n" or "Language: zh-tw\n"

Compile the messages and runserver again.

1

Not sure if you were able to resolve this later, but the problem is with the language directory names in the locale directory. This happens with all languages with a dash in their short-code. The solution is to rename the Chinese directories by replacing the dashes with underscores:

zh-cn --> zh_cn
zh-tw --> zh_tw

Hope this helps.

Taylan Pince
  • 443
  • 3
  • 10