django translation ngettext not working with gettext in the same file - django

this is my setup to generate translations for both singular and plurar text
from django.utils.translations import ngettext as _
from django.utils.translations import gettext
num = 3
my_plural_string = _("{num} apple", "{num} apples", num).format(num=num)
my_single_string = gettext("this is a text")
When using ngettext and gettext in the same file the generated .po file doesn't include the msgid_plural attribute for the first string
#: .\test_app\test_translation.py:10
msgid "{num} apple"
msgstr ""
#: .\test_app\test_translation.py:11
msgid "this is a text"
msgstr ""
I don't understand what is the problem in this code? Do I need to manually add the msgid_plural to each plural form of the strings ?

the weird part about this situation is if you change the imports like this
from django.utils.translation import ngettext
from django.utils.translation import gettext as _
It will work as expected :)

Related

Is there a better way to assign msgid in django translations?

I am currently relying on django translations and I am curious to know if there is a better way to pick msgid for translations rather than the usual approach.
For instance:
In order to mark something for translation you have to do the following.
variable_name = _("Some Name")
and Django picks the msgid in the following way
msgid "Some Name"
msgstr "Some Name"
I currently would like to see if there is a way in which I can either pass a key to gettext
_("my string", "my_key")
or
An implementation in which the variable name becomes the msgid automatically when django picks up the variable.
msgid "variable_name"
msgstr "Some Name"
Any idea or suggestion would be really helpful.
The msgid can't be overwritten, it's a source string for translation. But you can use the django.utils.translation.pgettext() function to provide a contextual information:
from django.utils.translation import pgettext
# Use pgettext to specify a custom ID and the original string
print(pgettext("variable_name", "Some Name"))
This will appear in the .po file as:
msgctxt "variable_name"
msgid "Some Name"
msgstr ""
In case your string needs pluralization, there is a django.utils.translation.npgettext() function:
from django.utils.translation import npgettext
def show_items(count):
message = npgettext(
'variable_name',
'You have one apple',
'You have {count} apples',
count
)
print(message.format(count=count))
show_items(1) # Output: You have one apple
show_items(3) # Output: You have 3 apples
This will appear in the .po file as:
msgctxt "variable_name"
msgid "You have one apple"
msgid_plural "You have {count} apples"

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}

NameError: global name 'styles' is not defined

This part of my code Paragraph('Road',style["Normal"], bulletText=None) gives me this NameError: global name 'styles' is not defined.
The module that I have importeded is :
from reportlab.lib.styles import ParagraphStyle
First make sure you have defined styles like this :
from reportlab.lib.styles import getSampleStyleSheet
styles = getSampleStyleSheet()
Also you can add other styles like "Justify"
You can do it this way (exemple with "Justify"):
from reportlab.lib.enums import TA_JUSTIFY
styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY))
text = "Hello World !"
story.append(Paragraph(text, style["Justify"]))
Then use it this way :
# create pdf
pdf = SimpleDocTemplate("your_doc.pdf")
# write in it
story = []
story.append(Paragraph(text, style["Justify"]))
# save it
pdf.build(story)
# return
return (frame)
And Here it is you have your pdf with styles !

Django - Internationalization won't work

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.