django i18n not working - django

A python newbie here.
I wanna my website support English and Chinese. So I just follow django book, chapter 19 internationalization. But it seems doesn't work for me, string I hope to be displayed as chinese, still english there. My code and settin is as following.
[settings.py]
LANGUAGE_CODE = 'zh-cn'
USE_I18N = True
USE_L10N = True
LANGUAGES = (
('en', 'English'),
('zh-cn', 'Chinese')
)
TEMPLATE_CONTEXT_PROCESSORS = {
'django.core.context_processors.i18n',
}
MIDDLEWARE_CLASSES = (
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
In my app views.py, I forcely set language code as 'zh-cn' in index
def index( request ):
response= render_to_response( 'index.htm' )
response.set_cookie('django_language','zh-cn')
return response
then I'd hope annother page that will be loaded after index.htm, will display a chinese string.
Annother page is renderred by upload.html
{% load i18n %}
<html>
<head>
{% block head %}
{% endblock %}
</head>
<body>
{% block body %}
<h1>{% trans 'Upload Demo' %}</h1>
{% endblock %}
</body>
</html>
After then, I do
django-admin.py makemessages -l zh-cn -e htm
in my django project folder, and I got django.po at
locale/zh-cn/LC_MESSAGES/django.po
which content is like
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-05-10 18:33+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL#ADDRESS>\n"
"Language-Team: LANGUAGE <LL#li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: uploader/template/base.htm:10
msgid "Upload Demo"
msgstr "上传文件"
Thereafter, I call following command to compile message
django-admin.py compilemessages
I got django.mo file at some folder with django.po
Fistly I access the index page, then I access another page, which has 'Upload Demo' string id. Actually I still see english string there.
And tried debug via printing language code, find that language has been set correctly.
context = RequestContext(request)
print context
translation.activate('zh-cn')
Lastly, I use
gettext locale/zh-cn/LC_MESSAGES/django.mo "Upload Demo"
really got 'Upload Demo'. So I think problem is here.
But why this happen? I really confused. Can any body help me.
Deeply appreciated any comment or help.
gettext locale/zh-cn/LC_MESSAGES/django.mo "Upload Demo"
I think I made a mistake. Above command return a string that is same as string you typed as string ID rather than translated string. In above command, it is "Upload Demo", That is if your change "Upload Demo" in above command as "bla bla", you will "bla bla".

Maybe it's too late, but I bet your problem probably was due to missing LOCALE_PATHS tuple in your project's settings.
After an hour of pulling my hair out, I solved the same problem by simply adding this to the settings.py file in my project:
LOCALE_PATHS = (
'/home/myuser/Projects/Some_project_root/My_django_project_root/locale',
)
And this is how that directory looks:
locale/
├── de
│   └── LC_MESSAGES
│   ├── django.mo
│   └── django.po
├── en
│   └── LC_MESSAGES
│   ├── django.mo
│   └── django.po
└── es
└── LC_MESSAGES
├── django.mo
└── django.po

Your codeblocks are a bit messy so it is quite hard to read it all. But you might want to start with your .mo file. It contains a #, fuzzy annotation. Fuzzy means that the build script was not sure about the translation and therefore requires attention of the translator (=you). Start by checking all #, fuzzy marked translations. If the translation is correct (or after you have corrected the wrong translation) remove the #, fuzzy annotation. Next run compile messages again. This could fix your problem.
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-05-10 18:33+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
See also: django fuzzy string translation not showing up
Friendly regards,
Wout

You can see LANGUAGE_CODE is not the same as django_language. I think get_language in utils.py does not handle underscore LANGUAGES correctly. get_language will return zh-cn but it should not be cut into cn. Instead, zh-cn should be converted to zh_CN.
So you should use below code in setting.py
LANGUAGES = (
('en', _('English')),
('zh-cn', _('Simplified Chinese')),
)
and run the following command from terminal
django-admin.py makemessages -l zh_CN
django-admin.py compilemessages
This is working perfectly for me

I believe the issue lies within the makemessages and compilemessages arguments that you are passing. #Vishnu's answer above is correct.
TLDR
Don't use zh-cn for the locale. Use zh_CN.
django-admin.py makemessages -l zh_CN
django-admin.py compilemessages -l zh_CN
Explanation
The "locale name" as defined in the Django Docs is:
A locale name, either a language specification of the form ll or a combined language and country specification of the form ll_CC. Examples: it, de_AT, es, pt_BR. The language part is always in lower case and the country part in upper case. The separator is an underscore.
In the makemessages example (found at the bottom of the makemessages documentation), you will notice the use of the locale name convention:
django-admin makemessages --locale=pt_BR
django-admin makemessages --locale=pt_BR --locale=fr
django-admin makemessages -l pt_BR
django-admin makemessages -l pt_BR -l fr
django-admin makemessages --exclude=pt_BR
django-admin makemessages --exclude=pt_BR --exclude=fr
django-admin makemessages -x pt_BR
django-admin makemessages -x pt_BR -x fr
You will notice the same in the compilemessages example:
django-admin compilemessages --locale=pt_BR
django-admin compilemessages --locale=pt_BR --locale=fr -f
django-admin compilemessages -l pt_BR
django-admin compilemessages -l pt_BR -l fr --use-fuzzy
django-admin compilemessages --exclude=pt_BR
django-admin compilemessages --exclude=pt_BR --exclude=fr
django-admin compilemessages -x pt_BR
django-admin compilemessages -x pt_BR -x fr

I have experienced a similar problem: compilemessagesseems to be working only on locale in the current directory. This was a remedy:
find . -name "locale" | while read VAR1; do CURR="``pwd``";cd $VAR1/..; echo "in $VAR1";django-admin.py compilemessages ; cd $CURR; done`

There is an outstanding problem in this code which is as follow:
In settings.py Make sure django.middleware.locale.LocaleMiddleware in the MIDDLEWARE setting comes after SessionMiddleware and CacheMiddleware and before CommonMiddleware if those other middlewares are used.
# settings.py
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.cache',
# ...
'django.middleware.locale.LocaleMiddleware',
# ...
'django.middleware.common.CommonMiddleware',
]
for more information see: 1 , 2

Related

django-admin makemessages --no-obsolete doesn't seem to be working

First of all, I am expecting --no-obsolete would comment out msgid and msgstr if gettext is deleted, right?
How I am testing is:
I wrote gettext("some string here") in view
I ran makemessages command
It wrote a .po file as expected
Then I deleted gettext() line from view and saved file, verified runserver working.
I ran makemessages --no-obsolete and it has not made any changes to .po file.
.po file content extract .
#. Translators: This message is a test of wrap line
#: servers/views.py:31
msgid "Do let me know if it works."
msgstr ""
dev environment
Django = 1.11
OS = Mac/Ubuntu 14.04
settings.py
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
LOCALE = (
os.path.join(os.path.dirname(__file__), "locale"),
)
Now with the help of Julien and Tarun, I found following observations.
python manage.py makemessages -l <locale>
If there is no gettext in the file being processed, the above command won't write/update .po file. That means if the corresponding .po file earlier had entries for msgstr and msgid, then it won't remove those entries unless file being processed had at least one gettext.
Note: Above behavior is irrespective of --no-obsolete
Now to make the --no-obsolete work as expected we need to follow the steps below.
First thing run python manage.py makemessages -l <locale>, this would write .po file with msgid and msgstr.
Now set msgstr and run python manage.py compilemessages -l <locale>. This command writes .mo file in the same directory as .po file.
Now next time when you run makemessages again (without --no-obsolete), .po and .mo files are compared and missing/deleted gettext are commented in .po file.
And when you run makemessages --no-obsolete, commented entries are removed from the .po file.
E.g
if you have 3 gettext entries, and you run makemessages first time, it would write 3 msgid and 3 msgstr in .po file. Now if you remove all gettext entries, .po file won't be updated after you run makemessages again, but if your keep at least 1 gettext entry in same file and run makemessages again, it would delete all msgid and msgstr for deleted gettext entries.
But if you run compilemessages after makemessages, .mo file is created and then for subsequent makemessages commands .po and .mo files are compared and then msgid and msgstr is commented in .po file for deleted gettext entries.
Then finally when you run makemessages with --no-obsolete option the commented messages from .po files are deleted permanently.
What the --no-obsolete does is to run a command called msgattrib with the --no-obsolete option on the content the po file. A typical case would be you generate your po file with makemessages, you get this:
#: servers/views.py:31
msgid "Do let me know if it works."
msgstr ""
Then you translate:
#: servers/views.py:31
msgid "Do let me know if it works."
msgstr "translation"
Then you remove the gettext entry, it'll still by default keep the translation, but mark it as obsolete.
#: servers/views.py:31
#~msgid "Do let me know if it works."
#~msgstr "translation"
If you set --no-obsolete option, then once your po file is done, it'll run msgattr with no-obsolete option. This will remove lines tagged with #~. See https://linux.die.net/man/1/msgattrib
But, the way makemessages is built, is that this will be called once the po file is written. But if there are no gettext in the files being processed, then it won't write to the po file. It'll just stop before getting to this msgattrib command. The po file you see is the one generated by the previous makemessages command. So the no-obsolete won't do anything.
There's no real solution to this. the no-obsolete option doesn't deal with the cases where you don't have any gettext to process.
So I think #JulienGrégoire was right about the fact that if there is no translation processed then the --no-obsolete won't work. There needs to be at least one translation captured for --no-obsolete to work.
But the solution to this quite simple. You can update your settings.py to define LANGUAGES like below
from django.utils.translation import ugettext_lazy as _
LANGUAGES = (
('en', _('English')),
('fr', _('French')),
)
Now your settings will always generate a translation. So it will make sure that you get --no-obsolete working every time you use it

Django only translating one word

I am attempting a navbar translation to simplified Chinese in Django, however, only the first word is being translated. To wit, I have created a navbar.html with the following content:
{% load i18n %}
<li>{% trans 'Home' %}</li>
<li>{% trans 'Security' %}</li>
I then do a ./manage.py makemessages -l zh_CN and constructed a file django.po which contains
#: templates/navbar.html:20
msgid "Home"
msgstr "首页"
#: templates/navbar.html:25
msgid "Security"
msgstr "安全性"
I then did a ./manage.py compilemessages to get the django.mo, which appears to have all the translations I need.
As opposed to this question, my LOCALE_PATHS is indeed a tuple:
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
and my LocaleMiddleware is after SessionMiddleware and before CommonMiddleware, as the documentation specifies:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
Yet nonetheless, only Home is translated; all other template variables are left untranslated.
To add a bit more mystery, I translated the navbar to Spanish and all variable were translated properly in the browser. This made me suspect my browser was not using the correct language code, so I ran ./manage.py makemessages -l zh-hans and copied over the translation from the zh_CN directory, but no dice.
Following this, I have removed all instances of #, fuzzy, to no avail.
I am on Django 1.10.3 and Python 3.5.

Django: mixed translations issue

I configured my application to support 2 languages: english and italian.
In my settings.py I specified i18n-related stuff as following:
USE_I18N = True
USE_L10N = True
USE_TZ = True
LANGUAGES = (
('en', 'ENGLISH'),
('it', 'ITALIAN'),
)
then I created a "locale" folder for each application and used the following commands to generate .po/.mo files:
django-admin.py makemessages -l en --no-location --no-obsolete
django-admin.py makemessages -l it --no-location --no-obsolete
django-admin.py compilemessages
All works fine, but I have a template where the two translations get mixed up (ie: part of the texts are in italian and other in english). I think that the problem is related to how my browser (Chrome) sends language headers (currently: Accept-Language: it,en-US;q=0.8,en;q=0.6).
Other browser on my machine like Firefox are sending: Accept-Language: en-US,en;q=0.5
Ok, this may be a personal problem related to a "strange browser configuration", but is not acceptable to have such result... how can I avoid this issue and have a coherent translation?
Is it possible that there is some content with origin from DB and thus not provided with translations?
On the other hand it may be the problem in rendering multiline fields in your .po files or .html files (make sure everything is {% trans ... %} wrapped.
Lastly if in Chrome you ask for translation in English when you are in the Italian site, does it provide you with all English content and vice verso?

Empty catalog when internationalizing JavaScript code

I'm trying to set up Internationalization of JavaScript code in my Django application.
My Django app has a locale subdirectory with a properly generated djangojs.po file. The package definition is as follows:
# urls.py
js_info_dict = {
'packages': ('my_project',),
}
./manage.py makemessages worked well as the .po file contains all the to-be-translated strings but no JavaScript string ever gets translated on the website and the catalog is always empty.
I also had some problems with. This is how it works for me:
Add this to yr root urls.py:
js_info_dict = { 'domain': 'djangojs',
'packages': ('YOUR_PROJECT_NAME',), }
urlpatterns = patterns('',
#enable using translation strings in javascript
#source: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#module-django.views.i18n
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)
In JS files use:
var somevar = gettext('Text to translate');
To compile django translation files: In a shell/terminal run from the project root (where 'apps', 'settings', etc lie):
#for "normal django files" (.py, .html):
django-admin.py makemessages --locale=de
#for javascript files. source: http://stackoverflow.com/a/3571954/268125
django-admin.py makemessages -a -d djangojs --locale=de
#to compile the translation files to machine code
django-admin.py compilemessages --locale=de
i added my_project to INSTALLED APPS in settings.py and that seemed to do the trick

How do I localize js templates in Django

I've the problem, template for dynamic JS file is main.js located in TEMPLATE_DIRS. When I do ./manage.py makemessages -a all messages {% trans "MSG" %} are fetched but not from main.js template.
Of course I can rename main.js to main.js.html, is any pretty way?
./manage.py makemessages -d djangojs — dont help.
You can specify extensions in makemessages command (see django docs):
django-admin.py makemessages -d djangojs -l de -e js -e html,txt