How to create language select in twig template - php

I'm currently using symfony 3.2. and now i have a link like this :
http://link.com?lang=en and in config/parameters I have allowed_locales -en, -ru
How could i create a language switcher in twig template like this :
EN<img src="{{ asset('assets/images/arrow-down.svg') }}" alt="arrow" class="arrow-down" />
<div class="locales-content" style="left:0;">
Russian
English
</div>

Here is what I did in my application, feel free to adapt it to your needs. It creates a dropdown with two links that redirect to the same page, but change the _locale parameter. In case there is no route in the request, it creates two links that redirect to the homepage.
<li class="dropdown">
{% if app.request.locale == 'ru' %}Russian{% else %}English{% endif %} <span class="caret"></span>
<ul class="dropdown-menu">
{# Check if there is a route and some parameters in the request #}
{% if app.request.get('_route') is not empty and app.request.get('_route_params') is not null %}
{# English #}
English
{# Russian #}
Russian
{# If there is no route in the request, redirect to the homepage #}
{% else %}
{# English #}
English
{# Russian #}
Russian
{% endif %}
</ul>
</li>

Related

Navigation on OctoberCMS with Static Pages plugin

I'm developing landing page with October CMS and using Static Pages plugin.
Here is my header.htm file with navigation:
<div class="header" id="header">
<div class="container">
<div class="header__inner">
<div class="header__logo">
<img src="{{ 'assets/img/logo.svg'|theme }}" alt="logo" class="logo">
</div>
<nav class="nav" id="nav">
{% partial 'menu-items' items=staticMenu.menuItems class='nav__list' %}
</nav>
</div>
</div>
</div>
Question is how to modify basic menu-items.htm partial if I'am using one page layout and I want exact section be active on menu item click (not separate page as it is now).
At the moment I have menu with such items and want one of these section be active on click:
/,
/#about,
/#projects,
/#contacts.
My menu-items.htm partial is below:
<ul class="{{ class }}">
{% for item in items %}
<li
class="nav__item {{ item.isActive or item.isChildActive ? 'active' : '' }}
{{ item.items ? 'dropdown' : '' }}"
>
<a class="nav__link"
{% if item.items %}class="dropdown-toggle" data-toggle="dropdown"{% endif %}
href="{{ item.url }}"
>
{{ item.title }}
{% if item.items %}<span class="caret"></span>{% endif %}
</a>
{% if item.items %}
{% partial 'menu-items' items=item.items class='dropdown-menu' %}
{% endif %}
</li>
{% endfor %}
</ul>
At the moment code in menu-items.htm partial if statement add "active" class on click because of this line:
<li class="nav__item {{ item.isActive or item.isChildActive ? 'active' : '' }} {{ item.items ? 'dropdown' : '' }}"
...it is because item "isActive" property is "true" when exact menu item is clicked. But my question is, how to do the same (add "active" class) with section link in meniu navigation, because my project have only one page "home" and several sections in it. so I want menu navigation link be active on fixed navigation when someone click for eaxmple "About" link and scroll to /#about section.
I wrote just several lines of Jquery (thanks to Pettis Brandon advise).
$('.nav__item').click(function(){
$('.nav__item').removeClass('active');
$(this).addClass('active')
});
It removes 'active' class from '.nav__item' class and after that add it again on corresponding link, based on {{ item.url }}. Hope it helps for the other as well (who is using Static Pages plugin).

Manually switch _locale in symfony 4

I'm absolutely stuck in getting a solution to manually switch the _locale variable in Symfony 4.
I followed these steps, but now I have absolutely no idea how to make a simple switch button in the nav section. I also took a look a this question, but this seems to be an older Symfony version..
Can anyone please help me climb out of this dark hole and explain to me how I can integrate a simple _locale switch button, or at least point me in the right direction?
The answer is slightly different from this answer which is not applicable in Symfony 4. Start with editing the services.yaml file in the config directory.
{# project/config/services.yaml}
# ...
parameters:
# ...
app_locales: [nl_NL, en_EN]
twig:
# ...
globals:
locales: %app_locales%
# ...
Then add a template to integrate the switch button somewhere in your base template.
{# project/templates/_locale_switcher.html.twig #}
{% set route = app.request.attributes.get('_route') %}
{% set route_params = app.request.attributes.get('_route_params') %}
{% set params = route_params|merge(app.request.query.all) %}
{# You may want to not print a flag/link for current view, the "if" here let
you handle it #}
{% for locale in locales if locale != app.request.locale %}
<li>
<a href="{{ path(route, params|merge({ _locale: locale })) }}">
<img src="{{ asset('img/flags/' ~ locale ~ '.jpg') }}" alt="{{
locale }}">
</a>
</li>
{% endfor %}
And finally integrate this brandnew template in your base template.
{# project/templates/base.html.twig #}
{% include '_locale_switcher.html.twig' %}
EDIT for Symfony 4.3.4+
As per the answer of Charles beneath, the locales value in services.yaml file should be inserted with quotes to avoid an unvalid YAML error:
{# project/config/services.yaml}
# ...
parameters:
# ...
app_locales: [nl_NL, en_EN]
twig:
# ...
globals:
locales: "%app_locales%"
# ...
As of latest Symfony (5.3.9), I strongly suggest one follows the documentation:
https://symfony.com/doc/current/the-fast-track/en/28-intl.html
Towards the end, do a bit of tweaking to generate a nice dropdown menu correctly based on your available languages:
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" id="locales">
<i class="fa fa-globe" aria-hidden="true"></i>
{{ app.request.locale|locale_name(app.request.locale)|u.title }}
</a>
<ul class="dropdown-menu" aria-labelledby="locales">
{% for locale in locales|split('|') %}
<li>
<a {% if app.request.locale == locale %}
class="dropdown-item active"
{% else %}
class="dropdown-item"
{% endif %}
href="{{ path(app.request.get('_route', 'app_index'), app.request.get('_route_params', [])|merge({_locale: locale})) }}">
{{ locale|locale_name(locale)|u.title }}
</a>
</li>
{% endfor %}
</ul>
</li>
</ul>
PS: The above is using Bootstrap 5.
Here is what works for me on latest symfony 4 version
services.yaml:
parameters:
locale: 'en'
app_locales: en|fr
twig:
globals:
locales: '%app_locales%'
locale template:
{# project/templates/_locale_switcher.html.twig #}
{% set route = app.request.attributes.get('_route') %}
{% set route_params = app.request.attributes.get('_route_params') %}
{% set params = route_params|merge(app.request.query.all) %}
{# You may want to not print a flag/link for current view, the "if" here let
you handle it #}
{% for locale in locales|split('|') %}
{% if locale != app.request.locale %}
<li>
<a href="{{ path(route, params|merge({ _locale: locale })) }}">
<img src="{{ asset('img/flags/' ~ locale ~ '.jpg') }}" alt="{{ locale }}">
</a>
</li>
{% endif %}
{% endfor %}

symfony twig include form_widget template

I'm using the following code to include a template for the data-prototype:
<ul class="factuurDetails list-unstyled"
data-prototype="{% filter escape %}{% include 'FactuurBundle:Default:prototypeCreditnotaDetail.html.twig' with {'form': form.creditnotaDetails.vars.prototype} %}{% endfilter %}">
{% for detail in form.creditnotaDetails %}
<li>
{{form_widget(detail) }}
</li>
{% endfor %}
</ul>
But how do I apply this same template prototypeCreditnotaDetail.html.twig to the {{form_widget(detail)}} ?

Multiple Header Styles In Timber/Twig

I'm coding up a theme using Timber for Wordpress, which uses the twig templating engine.
I currently have different data needed for header sections on three pages.
Home Page > BG Slider & Title
Blog Page > BG & Pinned Post
Other Pages > Regular BG Image
The navigation is also supposed to be the same over each of these page headers.
I'm unsure of the best way to use twig to solve this problem.
In my base.twig I currently have:
{% block header %}
<div class="wrapper">
<h1 class="hdr-logo" role="banner">
<a class="hdr-logo-link" href="/" rel="home">{{site.name}}</a>
</h1>
<nav id="nav-main" class="nav-main" role="navigation">
<ul class="nav">
{% for item in menu.get_items %}
<li class="nav-item {{item.classes | join(' ')}}">
<a class="nav-link" href="{{item.get_link}}">{{item.title}}</a>
{% if item.get_children %}
<ul class="nav nav-drop">
{% for child in item.get_children %}
<li class="nav-drop-item">
<a class="nav-link" href="{{child.get_link}}">{{child.title}}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</nav><!-- #nav -->
</div>
{% endblock %}
I could copy and paste this block onto each page, ie add it to
home.twig, blog.twig and other.twig
But i am repeating myself constantly, and it feels wrong. I need to feed through this on each page, without repeating my navigation each time i do it.
Does anyone have a suggestion as to how to fix?
What you want are Twig macros and/or Includes
Includes
can be used to include another .twig file in your template.
You can add variables to an Include also, but by default code inside the include have acccess to global context. eg. all template variables.
{# template.html will have access to the variables from the current context and the additional ones provided #}
{% include 'template.html' with {'foo': 'bar'} %}
{% set vars = {'foo': 'bar'} %}
{% include 'template.html' with vars %}
Macros
Are isolated from the global context, and can only work with variables/parameters that you supply to it.
{# defineit #}
{% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}
{# then calling it #}
<p>{{ _self.input('username') }}</p>
With both Includes and Macros you can easily do infinitely nested trees, when you include itself in the loop.
Example of nested tree with include:
{# content of tree.twig file for include#}
{% for item in menu.get_items %}
<li class="nav-item {{item.classes | join(' ')}}">
<a class="nav-link" href="{{item.get_link}}">{{item.title}}</a>
{% if item.get_children %}
<ul class="nav nav-drop">
{# recursion #}
{% include 'tree.twig' with { menu : item.get_children } %}
</ul>
{% endif %}
</li>
{% endfor %}

Remove percent sign on a percent field type

I've been googling around but I couldnt find the way to remove the percent sign that the Form Component (Symfony) adds to the percent field type when rendering a form. I've found something related to redefined the percent widget but I couldn't get it how this works, neither where to change it.
This is what I found:
You can overwrite the percent_widget block from the default layout to
something like this:
{% block percent_widget %}
{% spaceless %}
{% set type = type|default('text') %}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock percent_widget %}
My current rendering code inside the template is:
<div class="form-group">
{{ form_label(edit_form.discountRate, 'Discount', {'label_attr':{'class':'col-sm-2 control-label'}}) }}
<div class="col-sm-10">
<div class="input-group">
{{ form_widget(edit_form.discountRate, {'attr': {'class':'form-control'}}) }}
<div class="input-group-addon">%</div>
</div>
</div>
</div>
PD: Using the input-group class from boootstrap 3, I append that percent sign the way I like to render it, but how I delete the one that appends Symfony?
You have to override the default form theme of symfony 2.
First, open your app/config/config.yml file, and edit the twig configuration to have something like this :
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
form:
resources:
- YourBundleName:Form:my-form-theme.html.twig
(Its the form.resources part which is important). This configuration will tell Symfony 2 to use your custom theme.
You can also use {% form_theme form 'YourBundleName:Form:my-form-theme.html.twig' %} in your template if you don't want to add something in the config file, but I don't like to add this line in all my forms so I prefer to add it in global configuration.
Now you have to create a file src/YourBundlePath/Resources/views/Form/my-form-theme.html.twig with the following content :
{% extends 'form_div_layout.html.twig' %}
{% block percent_widget -%}
{% set type = type|default('text') %}
{{- block('form_widget_simple') -}}
{%- endblock percent_widget %}
And this should work.
If you open the theme file of Symfony 2 (/vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig) you can see that there is :
{% block percent_widget -%}
{% set type = type|default('text') %}
{{- block('form_widget_simple') -}} %
{%- endblock percent_widget %}
I removed the "%" on the 3d line in the override.
Regards
You cant remove it, its one of cons of symfony form % char is hardcoded
{% block percent_widget -%}
{% set type = type|default('text') %}
{{- block('form_widget_simple') -}} %
{%- endblock percent_widget %}
You can write your own block, where You will remove %
You just have to override the form theme in the template. There are several ways to do it.
I'm going to use the quickest.
Your template would end up like this:
{% form_theme edit_form _self %}
{% block percent_widget %}
{% spaceless %}
{% set type = type|default('text') %}
{{ block('form_widget_simple') }}
{% endspaceless %}
{% endblock percent_widget %}
<div class="form-group">
{{ form_label(edit_form.discountRate, 'Discount', {'label_attr':{'class':'col-sm-2 control-label'}}) }}
<div class="col-sm-10">
<div class="input-group">
{{ form_widget(edit_form.discountRate, {'attr': {'class':'form-control'}}) }}
<div class="input-group-addon">%</div>
</div>
</div>
</div>
Well no need to rewrite templates, the idea is to make a front removal with jQuery/JS. Most of the time your input is embedded in a div, and twig is generating something you like this :
<div class="a">
<input ...>
%
</div>
'%' text can be accessed and removed with native JS lastChild/removeChild functions :
$('.a').removeChild($('.a').lastChild) (jQuery/JS mix)
document.getElementsByClassname(a).removeChild(document.getElementsByClassname(a).lastChild) (plain vanilla JS)

Categories