I have a proyect with Django and I want to translate it to Spanish, English and Italian.
Everything working correctly in html files, but I have a file in .js that not working. Not translate any ids/key
<script src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static 'services_steps/file.js' %}"></script>
In file.js I have all ids in variables:
var whatever1 = gettext("filejs_whatever1")
var whatever2 = gettext("filejs_whatever2")
var whatever3 = gettext("filejs_whatever3")
Url.py
path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
url(r'^i18n/', include('django.conf.urls.i18n')),
if 'rosetta' in settings.INSTALLED_APPS:
urlpatterns += [
re_path(r'^rosetta/', include('rosetta.urls'))
]
And files.po get all ids (services_steps/locale)
...
#: file.js:70
msgid "filejs_whatever0"
msgstr "Whatever 0"
#: file.js:71
msgid "filejs_whatever1"
msgstr "Whatever 1"
#: file.js:72
msgid "filejs_whatever2"
msgstr "Whatever 2"
The commands are, in static (services_steps) folder:
django-admin makemessages -d djangojs -l en_GB
django-admin makemessages -d djangojs -l es_ES
django-admin makemessages -d djangojs -l it_IT
And in root directory
django-admin compilemessages
But ids has not been translated.
Doing i18n work with Python using Jinja2 and Pyramid. Seems to have a problem knowing how it should translate %%. I'm beginning to suspect the bug is in Jinja2.
So I've done some more investigation and it appears the problem is more with gettext than with jinja2 as illustrated with the repl
>>>gettext.gettext("98%% off %s sale") % ('holiday')
'98% off holiday sale'
>>>gettext.gettext("98%% off sale")
'98%% off sale'
>>>gettext.gettext("98% off %s sale") % ('holiday')
Traceback (most recent call last):
Python Shell, prompt 13, line 1
TypeError: %o format: a number is required, not str
It seems to be a chicken/egg problem.
If gettext translates %% -> % then the formatter blows up on it during parameter substitution.
If gettext doesn't translate %% -> % then when the formatter is not called (no params to insert) then the %% leaks out.
All this means the translators (most of whom are not computer programmers) have to be very careful in how they do the translation and everyone needs to be very careful with translations that include %.
Seems like we are doing this wrong (somehow) and there should be a more straightforward and uniform format for doing this. Right now we are coping by simply injecting a % as a format parameter.
Is there a better way to do this, or is this as good as it gets?
There is a .po file at the bottom
Unit test pretty much says it all, why is the last assertion failing? Is this a bug with Jinja2, or do I need to be dealing with this differently.
class Jinja2Tests(TestCase):
def test_percent_percent(self):
""" i18n(gettext) expresses 98% as 98%% only in some versions of jinja2 that has not
worked as expected. This is to make sure that it is working. """
env = Environment(extensions=['jinja2.ext.i18n'])
lang = gettext.translation('messages', path.abspath(path.join(path.dirname(__file__), 'data')))
env.install_gettext_translations(lang)
template = env.from_string(source="{{ _('98%% off %(name)s sale') | format(name='holiday') }}")
result = template.render()
self.assertEqual('98% off holiday sale(translated)', result)
template = env.from_string(source="{{ _('98%% off sale') }}")
result = template.render()
# THE LINE BELOW FAILS WITH:
# AssertionError: '98% off sale(translated)' != u'98%% off sale(translated)'
self.assertEqual('98% off sale(translated)', result)
And the MO file you have to compile to a PO file to run the above code.
# This file is distributed under the same license as the Uniregistrar project.
# FIRST AUTHOR <EMAIL#ADDRESS>, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: Uniregistrar 1.0\n"
"Report-Msgid-Bugs-To: mark#uniregistry.com\n"
"POT-Creation-Date: 2016-12-22 15:22-0500\n"
"PO-Revision-Date: 2016-11-14 16:42-0500\n"
"Last-Translator: FULL NAME <EMAIL#ADDRESS>\n"
"Language: en\n"
"Language-Team: en <LL#li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.3\n"
#: uniregistrar/constants.py:90
msgid "98%% off sale"
msgstr "98%% off sale(translated)"
#: uniregistrar/constants.py:90
msgid "98%% off %(name)s sale"
msgstr "98%% off %(name)s sale(translated)"
I've been developing an application which works in English or French (Canadian). Django settings are;
LANGUAGE_CODE = 'en'
LANGUAGES = [
('en', gettext('English')),
('fr-ca', gettext('Canadian French')),
]
LOCALE_PATHS = (
...
os.path.join(PROJECT_ROOT, 'console', 'locale'),
...
)
The app's locale path is console/locale/fr-CA/LC_MESSAGES/
The app however has recently stopped rendering the vast majority of the translations, while django debug toolbar, and other apps are displaying French without issue.
For example, I've got a form with 'First name', 'Last name', 'Email'. Yesterday this was correctly using the po file;
#: console/forms/participants.py:631
msgid "First Name"
msgstr "Prénom"
#: console/forms/participants.py:635
msgid "Last Name"
msgstr "Nom"
#: console/forms/participants.py:140 console/forms/participants.py:469
#: console/forms/participants.py:639 console/models/mixins.py:70
msgid "Email"
msgstr "Courriel"
But today, only the Email string is appearing in French. I assume ugettext is getting that from another application because I've tested it in the shell;
>>> from django.utils.translation import ugettext, activate
>>> activate('fr-ca')
>>> ugettext('Sunday')
u'dimanche'
>>> ugettext('Event')
u'Event'
>>> ugettext('Yes')
u'Oui'
>>> ugettext('Gender')
u'Gender'
>>> ugettext('enquiry')
u'enquiry'
>>> ugettext('Enquiry')
u'Enquiry'
>>> ugettext('Receive notifications about other events.')
u'Receive notifications about other events.'
These are all taken from the app's po file;
#: console/models/events.py:35 console/models/events.py:206
#: console/models/participants.py:81 console/models/vouchers.py:14
msgid "Event"
msgstr "Événement"
#: console/models/participants.py:113
msgid "Gender"
msgstr "Sexe"
#: console/models/participants.py:160
msgid "Receive notifications about other events."
msgstr "Recevez des notifications pour un événement."
It goes without saying I've ran the translation management commands (and can see the locale paths being output);
manage.py makemessages -l fr-CA
manage.py compilemessages -l fr-CA
You should remember that ugettext_lazy is a lazy evaluation and should be used in models and forms (as they load only once in Django) for views you should use gettext
Try delete (backup) translation files and recreate them again
Check templates for existence of translation blocks
When I create language file with django-admin makemessages -l I need them to be their msgstr equals not empty string but its msgid by default. Is it possible?
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