I try to get string translations working in Pyramid with ZPT templates. I followed the Pyramid guide on internationalization and localization, i.e. http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/i18n.html#chameleon-template-support-for-translation-strings.
However, when I add the line
<span>${some_translation_string}</span>
to my .pt template file I just get an assertion message from waitress:
NameError: some_translation_string
When I translate the string some_translation_string outside the ZPT templates (i.e. in the Python code of the view) it translates correctly. Thus, I think to have a valid compiled message catalog in place (though created manually due to missing Python3 support of babel/lingua).
I guess I misunderstand the way to insert localized strings in ZPT templates in general. It probably cannot be the same as for referencing variables?
As I understand now, translations within the ZPT template should look like this:
<span i18n:translate="">some_translation_string</h1>
If you omit the string identifier in i18n:translate the string itself is used for this.
Also you must add add the domain name in the template header, e.g.:
<html lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
i18n:domain="my_domain">
This information seems to be missing in the referenced Pyramid documentation.
For reference, to do translations for messages in your JavaScript code, I found this way handy:
In your view, add a TranslationStringFactory instance to the template parameters:
from translationstring import TranslationStringFactory
#view_config(route_name='site', renderer='templates/site.pt')
def form(request):
...
return {'_': TranslationStringFactory('yourapp')}
Then in the template you can write:
<script type="text/javascript">
...
yourapp.i18n['error'] = '${_('Error')}';
yourapp.i18n['warning'] = '${_('Warning')}';
</script>
Related
Lets say i have the following script in a html template of a flask application
<script type="text/javascript">
console.log('{{ url_for('root', arg1='hello', arg2='world') }}')
<script>
and i have a flask endpoint root()
#app.route('/', methods=['GET'])
def root():
print(print(request.args))
when i call my page the internal script is rendered to
console.log('/api/art_structure?arg2=world&arg1=hello')
When I call this url my request.args dict is:
ImmutableMultiDict([('amp;arg1', 'hello'), ('arg2', 'world')])
Which is not correct since the key of arg1 is wrong.
Any clues how I can prevent jinja2 from converting & to &?
The ampersand
The correct URL is /api/art_structure?arg2=world&arg1=hello.
The problem with the above URL is that ampersand (&) cannot be written directly in HTML, because the ampersand is used for entity references. For example, to write < character in HTML, which is not a tag start, one can write <. Because of that, to write &, one should escape it, i.e. write it as &.
Jinja2 templating engine does that by default. So, you can dump the contents of any string variable even if it contains special characters and they will be correctly escaped, e.g. & will become & as in your case.
How does that work?
So, if you actually put this in your jinja template: link, it would write the following HTML code: link, and if you clicked on the link in the browser, it would correctly replace & with & and open /api/art_structure?arg2=world&arg1=hello.
(note, however, that writing plain & as it is into HTML may sometimes also work, because browsers may guess how to fix the error)
So why does it not simply work in this case?
Because you are generating JavaScript and not HTML (you are generating code within <script> and </script>. In JavaScript, & is fine and should not be escaped, so you are free to write it as it is. To tell Jinja that you do not want it to escape the string, you can use the safe filter, i.e. {{ url_for('root', arg1='hello', arg2='world') | safe}}.
Try using safe
Ex:
console.log("{{ url_for('root', arg1='hello', arg2='world') | safe}}")
MoreInfo
I am using cookiecutter to create a tornado project, using this template (it has several bugs, so you'll probably won't be able to use it out of the box). I have hit a problem which I do not know how to solve:
jinja2.exceptions.TemplateSyntaxError: unexpected char '\\' at 124272
File "./{{cookiecutter.project_slug}}/static/swagger/lib/jsoneditor.min.js", line 10
I am not sure, but I have the impression that cookiecutter is trying to Jinja-process the jsoneditor.min.js, which is not supposed to happen, since the "templating" in that file is not supposed to be processed by cookiecutter, it just happens to include the same escape characters that Jinja is using.
Is it possible to tell cookiecutter not to process files inside a certain directory? This is probably a matter of properly setting up the cookiecutter template, but not sure how this can be specified.
By default cookiecutter will try to process every file as a jinja template which produces wrong results if you have something that looks like a jinja template but is only supposed to be taken literal. Starting with cookiecutter 1.1 one can tell cookiecutter to only copy some files without interpreting them as jinja template (documentation).
To do that you have to add a _copy_without_render key in the cookiecutter config file (cookiecutter.json). It takes a list of regular expressions. If a filename matches the regular expressions it will be copied and not processed as a jinja template.
Example
{
"project_slug": "sample",
"_copy_without_render": [
"*.js",
"not_rendered_dir/*",
"rendered_dir/not_rendered_file.ini"
]
}
This will not process any javascript files (files which end with .js), any files that are in the not_rendered_dir and not the not_rendered_file.ini in the rendered_dir. They will only get copied.
Just came across this question and also this Github Issue.
It seems like a nice addition, that one can partially mark parts of a file or entire template to not be processed by using the {% raw %} tag:
{% raw %}
{% comment %}Whatever jinja code goes here....{% endcomment %}
...
{% endraw %}
I started using custom inclusion tags within my django templates. For example I have a {% profilelink profile %} tag that inserts a link to a user profile together with a small version of the profile's picture, like so (profilelink.html):
<a href='{% url ... %}'><img src='{{ ... }}' alt='...'> {{ profile.name }}</a>
However, when I use it in the following snippet (sometemplate.html):
<p>Owned by {% profilelink owner %} (uploaded by {% profilelink uploader %})</p>
Then I get whitespace between the HTML produced by the second template tag and the closing parenthesis. This whitespace is unwanted. It comes from the final newline character in the file profilelink.html. This is a very common problem and searching Stackoverflow yields a lot of questions about whitespace in templates in general. Here's a summary of solutions found so far and why they don't work:
Some of these problems are solvable with the {% spaceless %} tag, but not all of them. This tag only removes whitespace between tags, which is not the case in the above example.
One possible solution is to not have a final EOL in profilelink.html but that's highly undesirable. Reasons: It is generally bad style; some editors (vim) silently add one back by default; that's how POSIX defines a line; it might make some SCMs unhappy; etc.
Another solution is switching to another template engine, like Jinja2, which may or may not solve this problem. It has support for constructs like {% ... -%} which eat the next EOL character. This is useful in some situations, but is also useless for my example above. But switching the templating backend for such a small annoyance seems a little overkill and adds another dependency. I'd like to stick to whatever is the standard "django" way of doing things. There are apparently plans to make Jinja2 the new Django default, though.
Some people suggested using a middleware class to remove redundant whitespace from the generated HTML before it's being sent to the browser. This is useful, but only for transforming the HTML in a way that is functionally equivalent, i.e. same semantics: it will then still be displayed the same way in the browser. That's not what I want, I want an actual change in semantics in order to have it display properly. This is impossible to implement in a generic middleware class. I need to have control over this on a case by case basis from within the template itself. I don't care about making the HTML prettier, I care about it being correct in the first place.
There's also bug #2594 which has been closed as WONTFIX with the argument (quote) "the Django template language is good enough for generating HTML, which isn't sensitive to whitespace". In my oponion this is just totally wrong. HTML is very much sensitive to whitespace, it just doesn't care how much there is of it. It cares a lot about whether there is some whitespace or none at all.
Some my question is: Is there any sane way to fix this problem in general? (One that always works, not just in some situations.)
(Any CSS-based fixes do not count. Copy/paste surprises are evil.)
I believe one solution is to use a simple_tag instead of an inclusion tag, hopefully without to much clutter.
I assume your tag is something like this:
#register.inclusion_tag('profilelink.html')
def profilelink(user):
return {"profile": user}
Would it be possible to substitute this with
from django.template.loader import render_to_string
#register.simple_tag
def profilelink(user):
t = render_to_string("profilelink.html", {"profile": user})
return t.strip()
I don't have a Django-project in front of me now, so this is untested.
This is the best I came up with so far. I still hope for a better solution, but for now it will do.
I defined a custom filter like this in base/templatetags/basetags.yp (taken from this answer):
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter
#stringfilter
def trim(value):
return value.strip()
And then use it as follows:
{% load basetags %}
<p>Owned by {% profilelink owner %} (uploaded by
{% filter trim %}{% profilelink uploader %}{% endfilter %})</p>
I want to create an engine in python that can replace tags in a template file with objects from json? I've loooked at python based engines that use regex but they are overly complicated and I am a little confused as to how to start an go about it. Any code to start would help
Sample json file
{
"webbpage": {
"title": "Stackoverflow"
},
"Songs": {
"name": "Mr Crowley"
},
"CoverArtists": [
{ "name": "Ozzy", "nicknames": ["Ozzman","Ozzster"] },
{ "name": "Slipknot", "nicknames": ["Slip"] }
]
}
Sample template file
<html>
<head>
<title><%% webbpage.title %%></title>
</head>
<body>
<h1><%% Songs.name %%></h1>
<%% EACH CoverArtists artist %%>
<%% artist.name %%>
<%% EACH CoverArtists.nicknames nickname %%>
<p><%% nickname %%></p>
<%% END %%>
<%% END %%>
</body>
</html>
Basically variables are identified between <%% and %%> and loops are identifed between <%% EACH .. %%> AND <%% END %%> and basically output html
Check out Alex Mitchells blog on templating (python based), it's extremely helpful, and the related GIT here
Basically,
Take input files on command line
Parse template file - build Abstract Syntax tree to parse easily. Create a node base type, and then for each new type implement a concrete class
Build stack to keep track of loops, pop when loops close, look for errors of missing loop ends
Parse json file, build dictionary of objects, map AST entries and replace in html
Write output to file.
I have a version of this based on Alex mitchells engine here, where I've fixed some issues with the original one( and put it in some code of my own) and will be trying to get rid of the reg exp based matching and put in contextual matching, because regular expressions dont work too well on large complex HTML data.
So basically you need to identify tokens within <%% and %%>. This step can be done with a regular expression, e.g. :
>>> import re
>>> t='<h1><%% Songs.name %%></h1>'
>>> re.search(r'<%%(.+?)%%>', t).groups()
(' Songs.name ',)
Parsing the code that this gives is quite a complicated task, and you might find some help in shlex or tokenizer. Even if you need to use regular expressions for the entire project, I suggest you take a look at these, and examples from other languages, to understand how a syntax parser works.
Once you've parsed the language, the next step is to replace the tokens with values from json. The best way would be to first load the data into python dicts, and then write a renderer to insert the data into the html.
Even if you can't use them, you should still have a look at some templating engines such as jinja or chameleon and study their source code to get an idea of how such a project is put together.
I would like to integrate Django, and the JavaScript prototype library to create an autocomplete feature for a form. Can anyone recommend a prototype feature that has been tried with Django? There is this code and also this and I'm wondering if anyone would recommend one over the other for use with Django. Thanks!
I downloaded the code from this site
and followed the directions there, which was straightforward. Just include the prototype.js, scriptaculous.js, and AutoComplete.js files. Then copy paste from the directions, and change the url from assets/ac.php?m=text&s= to ?m=text&s= or even just ?s= if one query parameter is all you need.
<input type="text" id="my_ac3" name="my_ac" size="45" autocomplete="off"/>
<script type="text/javascript">
new AutoComplete('my_ac3', '?s=', { delay: 0.25, resultFormat: AutoComplete.Options.RESULT_FORMAT_TEXT });
</script>
On the server side, in your view function for that page, start the function with:
if request.is_ajax():
#match the users input here, perhaps using data from your database and/or regular expressions
text = #response text to return, in my case since I chose Options.RESULT_FORMAT_TEXT as my resultFormat, it's a string where each autocomplete item is separated by '\n'
return HttpResponse(text, mimetype='text/plain') # mimetype is text here in my case
Then place the rest of the view function under an else clause.