Translate data from API in in template with an an other API - twig

im doing a package tracker with PHP / TWIG , and would like to translate results in an other language, so i have a google translate APi
in my twig file i have this :
{% for item in item.origin_info.trackinfo %}
<div class="status-{{item.checkpoint_status}}">
<p> {{item.StatusDescription}}. </p>
<hr/>
{% endfor %}
And i would like to translate each {{ item.StatusDescription }}. Could you tell me how to do ?
my function to translate is :
function translation($str){
$url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=fr&dt=t&q=" . $str;
$result = file_get_contents($url);
$data = json_decode($result);
$traduction = $data[0][0][0];
$lang = $data[2];
return $traduction;
}

You could register a custom filter into twig which allows you to call global functions.
$twig = new \Twig\Environment($loader);
$twig->addFilter(new \Twig\TwigFilter('translate', 'translation'));
First parameter translate is what the filter will be called in twig, the second is your global function translation. You now can use this filter in any template, e.g.
{% for item in item.origin_info.trackinfo %}
<div class="status-{{item.checkpoint_status}}">
<p> {{ item.StatusDescription | translate }}. </p>
<hr/>
</div>
{% endfor %}
If you need more than one extra function, filter, test, ... you are better off with creating an extension. See documentation for more information on this.

Related

How to check routes on template?

Does anyone know how to check if a template is being accessed through a url route with the django template language?
Here is my situation: There's this template article.html, that shows all posts of a blog when accessed through blog-home url route, and that also shows only posts of a given user through user-posts url route.
This template works like that because what defines which posts will be shown are the classes in views.py.
That being said, here is what I tried to do: (I know its wrong)
{% if url == 'user-posts' %}
"Some HTML h1 tag I want do be shown only when this template is accessed via 'user-posts' url"
{% endif %}
How would be the correct way, if there's any, to write this if statement?
When Django matches a url pattern a ResolverMatch object is created and made available on the request object at request.resolver_match. This ResolverMatch object can be queried in your template to acheive what you want, the url_name attribute is the name of the url pattern that was matched
{% if request.resolver_match.url_name == 'user-posts' %}
You should create a custom templatetag,
my_app/templatetags/utils.py
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def is_active_view(context, *view_names):
request = context.get('request')
for view_name in view_names:
if getattr(request.resolver_match, 'view_name', False) and request.resolver_match.view_name == view_name:
return True
return ''
And use it in your template this way, assuming blog-home is the url name you gave to your url :
blog-home.html
{% load utils %}
{% is_active_view 'blog-home' as display_blog_home_section %}
{% if display_blog_home_section %}
<!-- Your code -->
{% endif %}
NB : this template tag can check after multiple view names at once and support namespaced url :
{% is_active_view 'front:blog-home' 'front:blog-categories' as display %}
Here is a more optimized version of this if you are using boostrap and trying to make the menu options "active" when you are on that URL
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def is_active_tab(context, *view_names):
request = context.get('request')
for view_name in view_names:
if getattr(request.resolver_match, 'view_name', '') == view_name:
return 'active'
return ''
And you use it like
<li class="nav-item {% is_active_tab 'games:list' %}">
<a class="nav-link" href="{% url 'games:list' %}">
{% translate "My Quizzes" %}
</a>
</li>
<li class="nav-item {% is_active_tab 'games:create' %}">
<a class="nav-link" href="{% url 'games:create' %}">
{% translate "New Game" %}
</a>
</li>
It adds an extra active classname to the class of the element if any of the view_names match the current view name. Makes the template writing much cleaner

ACF with Timber&Twig - don't display on front page

I am new to Timber and Twig andnow I encountered problem I cannot solve. I use ACF in page templates and everything works fine but they do not display on front page. {{dump.(post.meta)}} is null
my front-page.php:
<?php
$context = Timber::context();
$context['post'] = new Timber\PostQuery();
$templates = array( 'pages/front-page.twig');
Timber::render( $templates, $context );
my front-page.twig:
{% extends "base.twig" %}
{% block content %}
{{dump(post.meta('header'))}}
<h1>{{post.meta('header')}}</h1>
<div class="hero__image__container">
<img src={{ Image(post.meta('img')).src }}/>
</div>
{% include 'parts/banner.twig' %}
{% include 'parts/services.twig' with {'items': services.get_items} %}#}
{% endblock %}
What am I doing wrong?
When you want to get a single post in Timber, you would use Timber::get_post().
<?php
$context = Timber::context();
$context['post'] = Timber::get_post();
$templates = array( 'pages/front-page.twig' );
Timber::render( $templates, $context );
When you use Timber\PostQuery, you get a collection of posts in return, which behaves like an array. Before you could use {{ post.meta() }}, you’d first have to access the first post in that array.

Show select field based on some other select option in flask

I am creating a flask form where I need to show a dropdown based on some other dropdown select field in Flask. I was able to do it with HTML, but finding it difficult to do the same in Flask form.
routes.py :
class RegistrationForm(FlaskForm):
category = SelectField('Category', choices = [('Clothes', 'Clothes'), ('Watch', 'Watch')])
subcategory = SelectField('Sub Category', choices = [('USPA', 'USPA'), ('LEE', 'LEE'), ('FOSSIL', 'FOSSIL'), ('TITAN', 'TITAN')])
submit = SubmitField('Register')
HTML :
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
<p>
{{ form.category.label }}<br>
{{ form.category }}<br>
{% for error in form.category.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.subcategory.label }}<br>
{{ form.subcategory }}<br>
{% for error in form.subcategory.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.submit() }}</p>
</form>
I want mapping link this :
Clothes : USPA, LEE
Watch : FOSSIL, TITAN
But in the form I am getting all the options. I need subcategory based on selected category.
Since this is dynamic functionality on the client side you will need to use Javascript.
Personally I think the easiest way to do this is pre configure your flask form statically:
class RegistrationForm(FlaskForm):
category = SelectField('Category', choices = [('Clothes', 'Clothes'), ('Watch', 'Watch')])
subcategory_clothes = SelectField('Sub Category', choices = [('USPA', 'USPA'), ('LEE', 'LEE')], validators=[Optional()])
subcategory_watches = SelectField('Sub Category', choices = [('Titan', 'Titan'), ('Fossil', 'Fossil')], validators=[Optional()])
submit = SubmitField('Register')
And then display either one or the other combo boxes dependent upon the value of the initial combo box, using Javascript if statement. You will need a javascript event hook to detect changes to category, or use a framework such as Vue.js.
An example of javascript hook is here https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onchange
You can add a javascript function, in HTML, to show either box depending on the value of the other checkbox:
<script>
function myFunction() {
let box_value = document.getElementById("category").value;
if (box_value === "Clothes") {
document.getElementById("subcategory_clothes").style.display = "initial"
document.getElementById("subcategory_watches").style.display = "none"
} else {
document.getElementById("subcategory_clothes").style.display = "none"
document.getElementById("subcategory_watches").style.display = "initial"
}
}
</script>
And you can add a render_keyword argument in Python so that it populates the event hook in HTML:
category = SelectField('Category', choices = [('Clothes', 'Clothes'), ('Watch', 'Watch')], render_kw={'onchange': "myFunction()"})

Dynamic nav-bar elements - passed from Flask to Jinja - inherited layout template

Environment: Python 3.6, Flask 1.02, Jinja2
Objective:
Create a dynamic menu in layout.html (which is extended by content.html)
yet the url_for of the dynamic element is frequently requires a parameter to be passed
Issue statement:
How can I pass the parameters for url_for in Jinja template when rendering the template?
I feel like I would need the syntax of str().format in Jinja..
I tried to:
1. pass each part as a separate value:
menus = [{'url': 'func_name', 'menu_title': 'title', 'param': 'param_name', 'param_val': 'param_value'}]
return render_template('content1.html', menus=menus]
in jinja I tried to call it like: (I also tried it without the plus and double-quotes)
{{ url_for(func_name), param_name+ "=" + param_val }}
During rendering it gives error of
url_for() takes 1 positional argument but 2 were given
2. tried to use the {% set var_name: passed_variable %}
Built on 1st version of menus defined on server side, I tried to set the variables within Jinja, but also failed.
menus = [{'url': 'func_name', 'menu_title': 'title', 'param': 'param_name', 'param_val': 'param_value'}]
return render_template('content1.html', menus=menus]
Jinja
{% for menu in menus %}
{% set url = menu.get('url') %}
{% set param = menu.get('param') %}
{% set value = menu.get('param_val') %}
{% url_for(url, param + "=" + value %}
Yet it also didn't work.
It feels like if I give a param for the url_for syntax (not a hard-wired string) I cannot add the parameters.
3. tried to pass whole content of url_for as a string:
menus={'url_string': " 'func_name', param_name=param_value"}
yet it fails again as url_for syntacs put the whole between apostrophes, which I wouldn't need at the end.
Some references I scanned through.
Flask context-processor
It could work if I would create another template of each nav-bar for each content page - yet with that move i could simply move the navbar into the content page. However that seems dull. Stack Overflow topic
Thus question:
How can I pass the
param_id=paramval['id']
for the url_for syntax during rendering
{{ url_for('edit_question', param_id=paramval['id']) }}
The code/structure stg like below:
layout.html
<html>
<body>
{% for menu in menus %}
{% for key, value in menu.items() %}
<a href="{{ url_for(value) }}" >
{{ key }}
</a>
{% endfor %}
{% endfor %}
{% block content %}
{% endblock %}
</body>
</html>
content1.html
{% extends 'layout.html' %}
{% block content %}
content
{% endblock %}
content2.html
{% extends 'layout.html' %}
{% block content %}
content
{% endblock %}
app.py
#app.route('/')
def index():
menus = [{'menu_title1': 'menu_func_name1'}]
return render_template('content1.html', menus=menus)
#app.route('/menu_details/<int:menu_nr>')
def show_details_of_menu(menu_nr):
menus = [{'menu_title3': 'menu_func_name3', 'menu_param_name': 'menu_param_value'}
return render_template('content2.html', menus=menus)
sorry for the Wall of text..
sigh.. after hours I just found how to construct the syntax. I hope it will help others!
During rendering:
menus = [{'url': 'func_name', 'menu_title': 'title', 'parameters': {'param1': param1_value}}]
return render_template('context.html', menus=menus]
In Jinja, I adjusted the syntax to manage cases where no parameters are needed:
{% for menu in menus %}
{% if menu.get('parameters').items()|length > 0 %}
<a href="{{ url_for(menu.get('url'), **menu.get('parameters')) }}">
{{ menu.get('menu_title') }}
</a>
{% else %}
<a href="{{ url_for(menu.get('url')) }}">
{{ menu.get('menu_title') }}
</a>
{% endif %}
{% endfor %}

html_entity_decode for twig (opencart)

im trying to output an attribute of a product on my product page (opencart v3).
The attribute is called 'technicaldetails' and it works just fine using this code:
{% if attribute_groups %}
{% for attribute_group in attribute_groups %}
{% if attribute_group.name == 'technicaldetails' %}
{% for attribute in attribute_group.attribute %}
{{ attribute.text }}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
but the technical details field have unstyled list stored in it.. and this outputs the complete html instead of rendering the list.
ive tried using {{ attribute.text|e }} and {{ attribute.text|raw }} and many other alternatives i could find.. but each time is just throws out the html and not render it..
in php this used to work.
<?php echo html_entity_decode($attribute['text']); ?>
so how can i decode the html now as i cant use php in twig and there is no html_entity_decode in twig either :(
looking forward for somehelp :)
much appreciated
thanks.
Just register the html_entity_decode function in twig.
The most simple way is to look where twig is loaded and add the following code,
$twig->addFilter(new \Twig_Simple_Filter, 'html_entity_decode', 'html_entity_decode');
After that you can just do the following in your twig templates
{{ attribute.text|html_entity_decode }}
UPDATE: For Opencart 3.0.3.7 version filter should be like this:
$twig->addFilter(new \Twig\TwigFilter('html_entity_decode','html_entity_decode'));
Find file
document_root/system/library/template/twig.php
Just after
$this->twig = new \Twig_Environment($loader, $config);
add following code
$twig->addFilter(new \Twig_SimpleFilter('html_entity_decode', 'html_entity_decode'));
After doing this, you must went to admin to reload all modifications in menu Extensions -> modifications.
After that you can do the following in all twig files *.twig
{{ attribute.text|html_entity_decode }}

Resources