Django translations not showing from app's po - django

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

Related

How to translate .po file

I have a flask app and i wanted to add multiple languages to it. So i have using this demo on Flask_babel to do this.
Flask Label Demo
config.py
DEBUG = True
LANGUAGES = ['en', 'de', 'fr']
This is the app.py
from flask import Flask, request, g
from flask_babel import Babel
from config import Config
# set up application
app = Flask(__name__)
app.config.from_object(Config)
# set up babel
babel = Babel(app)
#babel.localeselector
def get_locale():
if not g.get('lang_code', None):
g.lang_code = request.accept_languages.best_match(app.config['LANGUAGES'])
return g.lang_code
babel.cfg
[python: app/**.py]
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape, jinja2.ext.with_
To start the process i first used this command
pybabel extract -F babel.cfg -o messages.pot .
and then this
pybabel init -i messages.pot -d app/translations -l de
It generates messages.po file
# German translations for PROJECT.
# Copyright (C) 2021 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL#ADDRESS>, 2021.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL#ADDRESS\n"
"POT-Creation-Date: 2021-05-28 19:07+0530\n"
"PO-Revision-Date: 2021-05-28 19:08+0530\n"
"Last-Translator: FULL NAME <EMAIL#ADDRESS>\n"
"Language: de\n"
"Language-Team: de <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.9.1\n"
#: app/blueprints/multilingual/routes.py:38
msgid "Beautiful day in Portland!"
msgstr ""
#: app/blueprints/multilingual/routes.py:42
msgid "The Avengers movie was so cool!"
msgstr ""
#: app/blueprints/multilingual/routes.py:45 app/templates/base.html:15
msgid "Home"
msgstr ""
#: app/blueprints/multilingual/routes.py:51
msgid "The Cake is a Lie"
msgstr ""
#: app/blueprints/multilingual/templates/multilingual/cake.html:4
msgid "Hi, User!"
msgstr ""
#: app/blueprints/multilingual/templates/multilingual/cake.html:6
msgid "I promise you that there will be "
msgstr ""
#: app/blueprints/multilingual/templates/multilingual/cake.html:6
msgid "cake"
msgstr ""
#: app/blueprints/multilingual/templates/multilingual/cake.html:6
msgid " at the end of this article, so keep on reading!"
msgstr ""
#: app/blueprints/multilingual/templates/multilingual/index.html:4
msgid "Hi, "
msgstr ""
#: app/blueprints/multilingual/templates/multilingual/index.html:6
msgid " says: "
msgstr ""
#: app/templates/base.html:6
msgid "Welcome to Microblog"
msgstr ""
#: app/templates/base.html:16
msgid "Cake"
msgstr ""
How do i translate each and every msgid. The demo says to do this manually, but this is a demo and it only contains 10 lines but my project would contain hundreds of translations in 10 languages, so what do i use for that?
How do i convert the untranslated .po file to translated .po file by a library or program?
You can set up your own automated translation via deepl.com or any other translation api or you need to do it all by yourself with a help of an po editor.
Someone made this tool online https://www.ajexperience.com/po-translator/
It allows you to paste .po-files contents and choose the source language and target language. Tested, working.

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 localization: how to create language file with msgstr = msgid

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?

django i18n not working

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