Django javascript translation gettext always shows translated strings - django

The django gettext translation always displays the translated phrase (English), never my original phrase in the html (Dutch).
Normal translation with {% trans "" %} works well. Only the javascript gives this problem.
I don't have a /locale/nl/, as my default strings are already in Dutch.
I've set the translation up as in documentation (in settings, urls.py and html), and with gettext('string') in Javascript file. The Django catalog in http://localhost:8081/jsi18n/ shows the original Dutch strings:
django.catalog = {
"<p>De sluitdatum is verlopen op ": "<p>The closing date has passed on ",
"<p>De vragenlijst is ": "<p>The questionnaire is ",
"<p>U bent nog niet geaccepteerd voor deze vragenlijst.</p><p>U ontvangt een uitnodiging per email wanneer u bent geaccepteerd!</p>": "<p>You are not yet accepted for this survey.</p><p>You will receive an invitation by email when you are accepted!</p>",
"<p>U heeft de vragenlijst voltooid!</p> <p><small>U kunt uw antwoorden nog aanpassen tot de vragenlijst is gesloten.</small></p>": "<p>You have completed the questionnaire!</p> <p><small>You can change your answers until the survey close date</small></p>",
"Er zijn dubbele emailaddressen gevonden: ": "There are duplicate emailaddresses",
"Volgende": "Next",
"Vorige": "Previous"
};
But these sentences never get shown, in Dutch.

I think you forgot add translated strings in your djangojs.po file (for original default locale. Dutch in this case).
Or maybe you should add javascript-catalog url inside i18n_patterns():
i18n_urlpatterns = i18n_patterns(
url(r'^jsi18n/$', javascript_catalog, js_info_dict, name='javascript-catalog'),
)
urlpatterns += i18n_urlpatterns
Notice that in this case Django returns 2 different js files:
http://localhost:8000/en/jsi18n/
http://localhost:8000/ru/jsi18n/

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"

Django razorpay: How to get the order id after payment is complete

As per my understanding.
Step1) create Order_id
order_amount = 50000
order_currency = 'INR'
order_receipt = 'order_rcptid_11'
notes = {'Shipping address': 'Bommanahalli, Bangalore'} # OPTIONAL
obj = client.order.create(amount=order_amount, currency=order_currency, receipt=order_receipt, notes=notes)
then save order in databas
order_id = obj['id']
Orders(
id=order_id,
status="pending",
user=user,
razorpay_payment_id="",
razorpay_order_id="",
razorpay_signature="").save()
Step2 - Pass the order_id to the checkout page
<form action="https://www.example.com/payment/success/" method="POST">
<script
src="https://checkout.razorpay.com/v1/checkout.js"
data-key="YOUR_KEY_ID" // Enter the Test API Key ID generated from Dashboard → Settings → API Keys
data-amount="29935" // Amount is in currency subunits. Hence, 29935 refers to 29935 paise or ₹299.35.
data-currency="INR"//You can accept international payments by changing the currency code. Contact our Support Team to enable International for your account
data-order_id="order_CgmcjRh9ti2lP7"//Replace with the order_id generated by you in the backend.
data-buttontext="Pay with Razorpay"
data-name="Acme Corp"
data-description="A Wild Sheep Chase is the third novel by Japanese author Haruki Murakami"
data-image="https://example.com/your_logo.jpg"
data-prefill.name="Gaurav Kumar"
data-prefill.email="gaurav.kumar#example.com"
data-theme.color="#F37254"
></script>
<input type="hidden" custom="Hidden Element" name="hidden">
</form>
Step3: Get the reponse on payment completed
{
"razorpay_payment_id": "pay_29QQoUBi66xm2f",
"razorpay_order_id": "order_9A33XWu170gUtm",
"razorpay_signature": "9ef4dffbfd84f1318f6739a3ce19f9d85851857ae648f114332d8401e0949a3d"
}
Now We have to verify this.
But here we dont know this response is for which order_id as per this image.
Because i have seen someone using the below to retrieve the order
Orders.objects.get(order_id = razorpay_order_id)
but this contradicts with the notes in the above image.
If order_id is not same razorpay_order_id then the only way to retrieve the order is it to include it in the callback url like /successs/order_id
So how to do this the right way
Also one more confusing thing i found is that the python library razorpay is different from the docs
And what the docs say:
and again another confusion is the docs says we can use the python module
In step 1, with obj = client.order.create() and obj['id'] what you are getting is the order_id, and you have to save it in the DB corresponding to the Order.
We can blindly trust this created order_id since this is created in our server.
And on completing the checkout process of the order, the Razorpay returns razorpay_order_id, this will be the same as our order_id unless someone manipulated it. That's why the documentation says:
Do not use the razorpay_order_id "returned by the Checkout"
What does it actually mean is Do not use the razorpay_order_id "returned by the Checkout" directly in the
client.payment.capture(response['razorpay_payment_id'], ... )
without any validations or cross-checking with our previously created order_id
How to return the order?
Since we have already saved our Order with the order_id,
we can cross-check the razorpay_order_id with our order_id like in the example you mentioned.
trusted_order = Orders.objects.filter(order_id=razorpay_order_id)
if there exists a trusted_order that is not previously paid then we are safe to use razorpay_payment_id.

Extracting CVE Info with a Python 3 regular expression

I frequently need a list of CVEs listed on a vendor's security bulletin page. Sometimes that's simple to copy off, but often they're mixed in with a bunch of text.
I haven't touched Python in a good while, so I thought this would be a great exercise to figure out how to extract that info – especially since I keep finding myself doing it manually.
Here's my current code:
#!/usr/bin/env python3
# REQUIREMENTS
# python3
# BeautifulSoup (pip3 install beautifulsoup)
# python 3 certificates (Applications/Python 3.x/ Install Certificates.command) <-- this one took me forever to figure out!
import sys
if sys.version_info[0] < 3:
raise Exception("Use Python 3: python3 " + sys.argv[0])
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
#specify/get the url to scrape
#url ='https://chromereleases.googleblog.com/2020/02/stable-channel-update-for-desktop.html'
#url = 'https://source.android.com/security/bulletin/2020-02-01.html'
url = input("What is the URL? ") or 'https://chromereleases.googleblog.com/2020/02/stable-channel-update-for-desktop.html'
print("Checking URL: " + url)
# CVE regular expression
cve_pattern = 'CVE-\d{4}-\d{4,7}'
# query the website and return the html
page = urlopen(url).read()
# parse the html returned using beautiful soup
soup = BeautifulSoup(page, 'html.parser')
count = 0
############################################################
# ANDROID === search for CVE references within <td> tags ===
# find all <td> tags
all_tds = soup.find_all("td")
#print all_tds
for td in all_tds:
if "cve" in td.text.lower():
print(td.text)
############################################################
# CHROME === search for CVE reference within <span> tags ===
# find all <span> tags
all_spans = soup.find_all("span")
for span in all_spans:
# this code returns results in triplicate
for i in re.finditer(cve_pattern, span.text):
count += 1
print(count, i.group())
# this code works, but only returns the first match
# match = re.search(cve_pattern,span.text)
# if match:
# print(match.group(0))
What I have working for the Android URL works fine; the problem I'm having is for the Chrome URL. They have the CVE info inside <span> tags, and I'm trying to leverage regular expressions to pull that out.
Using the re.finditer approach, I end up with results in triplicate.
Using the re.search approach it misses CVE-2019-19925 – they listed two CVEs on that same line.
Can you offer any advice on the best way to get this working?
I finally worked it out myself. No need for BeautifulSoup; everything is RegEx now. To work around the duplicate/triplicate results I was seeing before, I convert the re.findall list result to a dictionary (retaining order of unique values) and back to a list.
import sys
if sys.version_info[0] < 3:
raise Exception("Use Python 3: python3 " + sys.argv[0])
import requests
import re
# Specify/get the url to scrape (included a default for easier testing)
### there is no input validation taking place here ###
url = input("What is the URL? ") #or 'https://chromereleases.googleblog.com/2020/02/stable-channel-update-for-desktop.html'
print()
# CVE regular expression
cve_pattern = r'CVE-\d{4}-\d{4,7}'
# query the website and return the html
page = requests.get(url)
# initialize count to 0
count = 0
#search for CVE references using RegEx
cves = re.findall(cve_pattern, page.text)
# after several days of fiddling, I was still getting double and sometimes triple results on certain pages. This next line
# converts the list of objects returned from re.findall to a dictionary (which retains order) to get unique values, then back to a list.
# (thanks to https://stackoverflow.com/a/48028065/9205677)
# I found order to be important sometimes, as the most severely rated CVEs are often listed first on the page
cves = list(dict.fromkeys(cves))
# print the results to the screen
for cve in cves:
print(cve)
count += 1
print()
print(str(count) + " CVEs found at " + url)
print()

Python lxml xpath no output

For educational purposes I am trying to scrape this page using lxml and requests in Python.
Specifically I just want to print the research areas of all the professors on the page.
This is what I have done till now
import requests
from lxml import html
response=requests.get('http://cse.iitkgp.ac.in/index.php?secret=d2RkOUgybWlNZzJwQXdLc28wNzh6UT09')
parsed_body=html.fromstring(response.content)
for row in parsed_body.xpath('//div[#id="maincontent"]//tr[position() mod 2 = 1]'):
for column in row.xpath('//td[#class="fcardcls"]/tr[2]/td/font/text()'):
print column.strip()
But it is not printing anything. I was struggling quite a bit with xpaths and was intially using the copy xpath feature in chrome. I followed what was done in the following SO questions/answers and cleaned up my code quite a bit and got rid of ' tbody ' in the xpaths. Still the code returns a blank.
1. Empty List Returned
2. Python-lxml-xpath problem
First of all, the main content with the desired data inside is loaded from a different endpoint via an XHR request - simulate that in your code.
Here is the complete working code printing names and a list of research areas per name:
import requests
from lxml import html
response = requests.get('http://cse.iitkgp.ac.in/faculty4.php?_=1450503917634')
parsed_body = html.fromstring(response.content)
for row in parsed_body.xpath('.//td[#class="fcardcls"]'):
name = row.findtext(".//a[#href]/b")
name = ' '.join(name.split()) # getting rid of multiple spaces
research_areas = row.xpath('.//*[. = "Research Areas: "]/following-sibling::text()')[0].split(", ")
print(name, research_areas)
The idea here is use the fact that all "professor blocks" are located in td elements with class="fcardcls". For every block, get the name from the bold link text and research areas from the following string after Research Areas: bold text.

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.