Django - Internationalization won't work - django

I have the following line of code which basically returns an error - a translated error - along with a view in a case of a failure:
from django.utils.translation import ugettext_lazy as _
.....
return render_to_response('login.html',{'form': form,'error_message':_("User is not in the group %s" % group_name),'settings':SettingsManager.get()},context_instance=RequestContext(request))
And I created the message files, and compiled them. But the thing is it is only displayed as I wrote it - in English, User is not in the group %s" % group_name. Part of my django.po file:
#: application/views.py:1003
#, python-format
msgid "User is not in the group %s"
msgstr "Kullanıcı %s grubunda değil."
ANy ideas how to solve it? I cannot see the problem.
P.S: All the other translations are working like a charm, but this one is not.
Thanks in advance.

Try
_("User is not in the group %s") % group_name
instead of
_("User is not in the group %s" % group_name)
that way the translation machinery has a constant string to look up.

Related

How to return a lazy translation object with placeholders?

In my Django v1.6.5 project running on Python v2.7.x, I have a Model that returns its configuration as a string. I need the returned string to be a gettext_lazy object, so I can evaluate it in any language required later.
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _, string_concat
...
class MyModel(models.Model):
key = models.CharField(...)
value = models.CharField(...)
#property
def config_str(self):
return _('some configuration')
This seems to work fine in these scenarios:
Static string: (see above) - works!
String concatenation: return string_concat(self.key, _(' equals '), self.value) - works!
What is not working, is using gettext_lazy with placeholders, a la:
return _('“%(key)s” equals “%(value)s”' % {key: self.key, value: self.value})
or using the .format() mechanism:
return _('“{key}” equals “{value}”').format(key=self.key, value=self.value)
When I do this, my .po file does contain:
#, python-format
msgid "“%(key)s” equals “%(value)s”" or
msgid "«{key}» equals «{value}»"
but even when I populate this Eg.:
msgstr "«%(key)s» est égal à «%(value)s»" or
msgstr "«{key}» est égal à «{value}»"
and I run compilemessages, the translation seems to be ignored. When I translate the promise returned by the model instance, I always get an EN string with the placeholders filled E.g., '“foo” equals “bar”'. Note, I get an EN string even when the first calling context is FR (for example). This tells me that the translations just aren't even occurring. It is my theory that by the time I eval the lazy object, gettext is looking for the literal string "“foo” equals “bar”" (for example) in the translation catalog rather than something with placeholders and named values.
With this in mind, I've also tried wrapping the whole format() in the lazy object like this:
return _('“{key}” equals “{value}”'.format(key=self.key, value=self.value))
But it seems to have made zero difference. =/
I can get by with string_concat() for now, but sometimes, the placeholders will need to be moved around in some translations, so I'd like to figure this out.
I'm beginning to think that one simply cannot use placeholders with gettext_lazy.
NOTE: I have reviewed django: Translation with variables inside, but a) that has no accepted answer and b) he's using gettext, not gettext_lazy.
OK, the solution here is to provide an extra layer of laziness (Thanks, Django core dev: Florian Apolloner AKA “apollo13”).
Here's my modified function that WORKS:
from django.utils import six
from django.utils.functional import lazy
class MyModel(models.Model):
key = models.CharField(...)
value = models.CharField(...)
#property
def configuration_string(self):
def wrapper():
return _('“{key}” equals “{value}”').format(
key=self.key,
value=self.value
)
return lazy(
wrapper,
six.text_type
)
The only thing is, where I use this, I must remember to eval the wrapper function as follows:
from django.utils.encoding import force_text
config = my_model_instance.configuration_string
# NOTE: Evaluate the lazy function wrapper inside the force_text()
config_str = force_text(config())
Now, in my case, I need to support cases where 3rd party devs write the function configuration_string returning either the lazy function wrapper, a lazily evaluated translation string or just a regular string, so I use:
import types
from django.utils.encoding import force_text
from django.functional import Promise
config = my_model_instance.configuration_string
if isinstance(config, types.FunctionType):
config_str = force_text(config())
elif isinstance(config, Promise):
config_str = force_text(config)
else:
config_str = config
Thanks again to Apollo13 for guidance!
I had a very similar problem and found that using gettext_noop instead of gettext_lazy worked for me available since Django 1.11.

django: Translation with variables inside

I have the following piece of code:
from django.utils.translation import ugettext as _
task = _('You have %s friends') %(c1.task)
// This is translation
#: compositions/views.py:69
#, fuzzy, python-format
msgid "You have %s friends"
msgstr "У вас %s друга"
But for some reason this msgstr does not work...
Maybe try using string placeholders - from the django documentation:
The strings you pass to _() or ugettext() can take placeholders,
specified with Python’s standard named-string interpolation syntax.
Example:
def my_view(request, m, d):
output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
return HttpResponse(output)
Applying this to your example, you'd get:
task = _('You have %(num_friends)s friends') % {'num_friends': c1.task}

weird django translations behaviour

I have weird problem with django translations that i need help figuring out. Problem is that instead of getting translated string every time i seem to get randomly either translated string or default string.
I have created a class for putting "action" buttons on several pages. Many of those buttons are reusable so why should i put
blabla
into several templates when i can create simple toolbar and use
toolbar.add(tool)
in view and then just use templatetag for rendering all the tools.... anyway.
This is example of one tool:
class NewUserGroupButton(MyTool):
tool_id = 'new-user-group'
button_label = ugettext(u'Create new user group')
tool_href = 'new/'
js = ()
def render(self):
s = '<a id="%(tool_id)s" href="%(tool_href)s" class="button blue">%(button_label)s</a>'
return s % {'tool_id': self.tool_id, 'tool_href': self.tool_href, 'button_label':self.button_label}
The tools are rendered like this:
class ToolbarTools:
def __init__(self):
self.tools = []
def add(self, tool):
self.tools.append(tool)
def render(self):
# Organize tools by weight
self.tools.sort(key=lambda x: x.weight)
# Render tools
output = '<ul id="toolbar" class="clearfix">'
for tool in self.tools:
output += '<li id="%s">' % ('tool-'+ tool.tool_id)
output += tool.render() if tool.renderable else ''
output += '</li>'
output += '</ul>'
# Reset tools container
self.tools = []
return mark_safe(output)
im using ugettext to translate the string. using (u)gettext=lambda s:s or ugettext_lazy gives me either no translations or proxy object corresponding to function choices.
And like i said - while rest of the page is in correct language the toolbar buttons seem to be randomly either translated or not. The faulty behaviour remains consistent if i move between different pages with different "tools" or even refresh the same page several times.
Could someone please help me to figure out what is causing this problem and how to fix it?
Problem solved.
The issue itself (random translating) was perhaps caused by using ugettext. But at the same time i should have used ugettext_lazy instead.
And thus the problem really came from ugettext_lazy returning proxy object not translated string... and that is caused by this:
[Quote]
Working with lazy translation objects
The result of a ugettext_lazy() call can be used wherever you would use a unicode string (an object with type unicode) in Python. If you try to use it where a bytestring (a str object) is expected, things will not work as expected, since a ugettext_lazy() object doesn't know how to convert itself to a bytestring. You can't use a unicode string inside a bytestring, either, so this is consistent with normal Python behavior. For example:
This is fine: putting a unicode proxy into a unicode string.
u"Hello %s" % ugettext_lazy("people")
This will not work, since you cannot insert a unicode object
into a bytestring (nor can you insert our unicode proxy there)
"Hello %s" % ugettext_lazy("people")
[/Quote]
taken from here:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#working-with-lazy-translation-objects
Alan
I had the same issue just now. The problem was caused by incorrect Middleware order - I set LocaleMiddleware after CommonMiddleware. After I placed it between SessionMiddleware and CommonMiddleware, it seems to work correctly.
See more here: https://lokalise.com/blog/advanced-django-internationalization/
I know, the problem was solved a long ago, but it can be helpful for someone.

Django Logging i18n ugettext_lazy Variables

I'm having trouble logging the output of an internationalized django variable.
My application code used the 'message' vaiable OK and it displays
in English and German (the two languages I am working with)
My problem is when I try to make a log of the said 'message' variable output.
I want to log in English and/or German (depending on what the end user is seeing)
I'm using string_concat and it says:
the lazy translations in result will only be converted to strings when result
itself is used in a string (usually at template rendering time).
Here is a code sample:
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
message = _('Profile Updated OK')
# Build a log message
fmt_msg = _(message)
log_message = 'Message Sent: '
log_message = string_concat(log_message, fmt_msg)
logger.info(log_message)
The log entry is not translated:
Message Sent: <django.utils.functional.__proxy__ object at 0x9c3c4ac>
Can anyone suggest how I can have the proxy object to be translated
when used with logging?
It's translating OK in my regular Django code just the logging.info() issue.
Cheers!
From the docs:
The result of a ugettext_lazy() call can be used wherever you would use a unicode string (an object with type unicode) in Python. If you try to use it where a bytestring (a str object) is expected, things will not work as expected, since a ugettext_lazy() object doesn't know how to convert itself to a bytestring.
Also, don't call _() twice.
logger.info(u'Message Sent: %s' % message)
You have to force Unicode strings, as documented in http://www.djangobook.com/en/2.0/chapter19/
u"Hello %s" % ugettext_lazy("people")
And do not call the function twice ;)

Django: how do I include a url link in a form label

My use case looks very basic but I couldn't find anything on the web!
The idea is a form with checkbox "I have read and agree to the terms and conditions"
And a link on "terms and conditions" which points to a page with such terms and conditions...
Classic!
So I have a field in my form as follows:
tos = forms.BooleanField(widget=forms.CheckboxInput(),
label=_(u'I have read and agree to the terms and conditions' % reverse('terms_of_use')),
initial=False)
where 'terms of use' is the name of one of my url patterns in urls.py
But I get an error:
ImproperlyConfigured: The included urlconf urls doesn't have any patterns in it
My urlconf works fine on the whole site so I supposed that the problem was that the urlconf is not yet populated when the form is rendered ?
I tried using lazy_reverse = lazy(reverse, str) instead of reverse, but it doesn't solve anything.
Is there a way to make this work ? The use case seems very very basic so there surely is a way to do it without having to break up the form inside my template ?!
lazy_reverse won't work since you're turning around and unlazying it the second after with your "...%s..." % lazy(blah) notation.
I suppose you could try to lazy the whole thing, i.e.
label = lazy(lambda: _("bla %s bla" % reverse('something')))
but I did not test this
alternatively, just override the label at __init__, i.e.
self.fields['myfield'].label = 'blah %s bla' % reverse('bla')
I use this syntax
from django.urls import reverse
from django.utils.functional import lazy
privacy = forms.BooleanField(label = lazy(lambda: _("Privacy <a href='%s' a>policy</a>" % reverse('privacy'))))
You can provide a link a form label like this:
foo_filter=forms.ModelChoiceField(FooFilter.objects.all(),
label=format_html('{}', reverse_lazy('foo-filter'),
FooFilter._meta.verbose_name))
See AppRegistryNotReady: lazy format_html()?