Symfony2 translation in templates does not apply - symfony

I have this in my twig template:
{% trans %}lala{% endtrans %}
{{ 'Presentation'|trans|raw }}
and lots of not translatable twig html in between.
And the only way it applies translations is when in the controller action I call the translator:
$t = $this->get('translator')->trans('lala');
If I comment the line above, the translation does not occur. How can I force that? (Well, what am I doing wrong?)
For more info, this is my config.yml file:
framework:
translator: { fallback: %locale% }
default_locale: "%locale%"
And I get the locale variable through my routing:
my_bundle_name:
resource: "#MyBundle/Resources/config/routing.yml"
prefix: /{_locale}/add
requirements:
_locale: en|ja
EDIT:
The files are located like a normal symfony project.
my twig template is located in:
src/COMP/myBundle/Resources/views/entity1/new.twig.html
The only difference might be that it extends a base template which is located in
src/COMP/myBundle/Resources/views/base.html.twig
The translation are also located in the Resources folder:
src/COMP/myBundle/Resources/translations/messages.en.xlf
src/COMP/myBundle/Resources/translations/messages.ja.xlf
src/COMP/myBundle/Resources/translations/validators.ja.xlf
the controller is also located in the default place:
src/COMP/myBundle/Controller/myentitycontroller.php
I've been keeping developing with that trick, to explicitly call the translator, and now it suddenly works even without that workaround. And I am unable to repeat the same beheaviour as before.
I am still curious of why was that happening to me, but maybe I should delete the question...
My first guess is that I was trying to translate a template which was a "partial". I mean, from base.html.twig I was calling an action of a controller:
{{ render(controller('COMPMyBundle:Default:Welcome', {'aprequest': app.request})) }}
But I am unable to repeat the same beheaviour. (Before, when that was happening to me, and now, when I am trying to get the same beheaviour, I cleared the cache several times, so it shouldn't be that).

Related

How can I override **partially** a third-party template?

I need to override a template from third-party bundle by following one of the Symfony's built-in conventions. The Symfony documentation talks about them:
To override the bundle template, just copy index.html.twig template from the bundle to app/Resources/AcmeBlogBundle/views/Blog/index.html.twig (the app/Resources/AcmeBlogBundle directory won't exist, so you'll need to create it). You're now free to customize the template.
You can also override templates from within a bundle by using bundle inheritance. For more information, see How to Use Bundle Inheritance to Override Parts of a Bundle.
While this approach may work, it can be overly complicated if you only need to override a small portion of the template (e.g. some blocks). Additionally, if the third-party bundle updates its own template, your version of the template may become outdated and require updates to stay current with the latest changes.
This is what I've tried to do without success:
{# app/Resources/AcmeBlogBundle/views/Blog/layout.html.twig #}
{% extends '#AcmeBlog/Blog/layout.html.twig' %}
{% block title %}My Default Title{% endblock %}
The above code doesn't work. It breaks after reaching the maximum execution time when I've accessed this page and the clear cache command never ends.
Why it doesn't works and how to achieve it without copying the entire parent template from the third-party bundle?
Related issues and pull-requests without workaround:
https://github.com/symfony/symfony/issues/1966 (2011)
https://github.com/symfony/symfony/pull/2202 (2011)
https://github.com/symfony/symfony-docs/issues/752 (2011) | Unrelated.
https://github.com/twigphp/Twig/issues/1334 (2014)
https://github.com/symfony/symfony/issues/15755 (2015)
https://github.com/symfony/symfony/issues/17054 (2015)
https://github.com/symfony/symfony/issues/17407 (2016)
https://github.com/symfony/symfony/issues/17557 (2016)
Why it doesn't works?
{# app/Resources/AcmeBlogBundle/views/Blog/layout.html.twig #}
{% extends '#AcmeBlog/Blog/layout.html.twig' %}
{% block title %}My Default Title{% endblock %}
The reason comes from Twig's paths and namespaces auto-configuration between bundles, their children and Symfony's path convention. By default Symfony/Bundle/TwigBundle assign the same Twig's namespace (AcmeBlog) for all paths, following this order:
# config.yml
twig:
paths:
# Auto-configuration behind the scenes for TwigBundle extension:
# (1st) if AcmeBlogChildBundle has as parent to AcmeBlogBundle
'src/AcmeBlogChildBundle/Resources/views': AcmeBlog
# (2nd) Path to override bundles (Symfony's convention)
'app/Resources/AcmeBlogBundle/views': AcmeBlog
# (3rd) third-party bundle
'vendor/acme/blog-bundle/Resources/views': AcmeBlog
That means, if you need to render the #AcmeBlog/Blog/layout.html.twig template, Twig try to find it in all paths (in the order has been defined) whose namespace matches AcmeBlog.
So to override it, you had to create this template (/Blog/layout.html.twig) in (1st) or (2nd) paths. But, if you're extending from #AcmeBlog/Blog/layout.html.twig at the same time (thinking about extends from the original template) then Twig performs the same previous procedure, causing a circular template reference (infinite loop) and never reach the (3rd) path.
How to achieve it without copy the entire parent template from the third-party bundle?
Symfony's built-in workaround
Let's define a different Twig's namespace for this third-party bundle in twig paths configuration:
# config.yml
twig:
paths:
# (4th) third-party bundle alias.
# The path can be relative to project or real path
vendor/acme/blog-bundle/Resources/views: AcmeBlogOriginal
Later, use the namespace alias to avoid circular reference when you're overriding a third-party template that extends from the original:
{# app/Resources/AcmeBlogBundle/views/Blog/layout.html.twig #}
{% extends '#AcmeBlogOriginal/Blog/layout.html.twig' %}
{% block title %}My Default Title{% endblock %}
Thus, you're able to override blocks instead the whole template. Even should work out-of-the-box as it's about Twig's paths only.
Since Symfony 3.4 this issue has been solved as built-in feature.
http://symfony.com/blog/new-in-symfony-3-4-improved-the-overriding-of-templates#overriding-and-extending-templates

How to create internationalized static pages in symfony2?

I have a project (symfony 2.3) and I have some static pages, but i need i18n. What is the best way to achieve it?
I was trying something like this with specific twig templates for each locale, but not work.
static_about:
path: /{_locale}/about
defaults:
_controller: FrameworkBundle:Template:template
template: 'EscFrontendBundle:Static/{_locale}_about.html.twig'
problem:
While {_locale} in the path works with static content ...
... {_locale} in the route's template setting is not being replaced by symfony.
solution:
To overcome this just use a "base" twig template about.html.twig containing an include like this:
{% include app.request.locale ~ '_about.html.twig' %}

Detect the user's locale automatically

My goal is to recognize the local user's browser and automatically set the language.
Then allow the user to change language and keep it on other pages.
At the time I set the routes in this way:
# homepage not localized: load the homepage with default language
index_not_localized:
path: /
defaults: { _controller: "AcmeSiteBundle:Default:index", _locale: %locale% }
acme_site:
resource: "#AcmeSiteBundle/Controller/"
type: annotation
prefix: /{_locale}
defaults: { _locale: %locale% }
requirements:
_locale: %route_locale_requirements%
When the user enters the page example.com without specifying the language in the local route is set by default, and the page there is a switcher that allows you to change the language:
<ul class="dropdown-menu">
{% for locale in ['en', 'it'] %}
<li>
<a href="{{ path('homepage', {'_locale': locale}) }}">
</li>
{% endfor %}
</ul>
How do I do what I want?
I have to create a listener? I have put the local session?
I'm confused, I read several answers but have not found a clear answer!
There are at least two ways, but both of them don't gave you 100% guarantee to detect locale and detect it right.
The first is to use $_SERVER['HTTP_ACCEPT_LANGUAGE'] variable. It's gotten via HTTP Headers and can even doesn't exist.
The second is to use 3rd-side services to detect country by IP address and then compare country name to some local table of countries and their locales. For example:
http://api.hostip.info/get_html.php?ip=127.0.0.1
For more information and comments look at this question: Simplest way to detect client locale in PHP
And the final point is to integrate locale detection into the symfony2 project. This is the simplest part. You just need to use kernel.request event listner. Everything is perfectly explained (with examples) here: Symfony 2.1 set locale

Symfony KnpMenuBundle configuration across bundles

I'm using KnpMenuBudle in two different bundles of the same application. In one bundle I use also BraincraftedBootstrapBundle, so in my app/config/config.yml I put this specific config to style menus with bootstrap:
knp_menu:
twig:
template: "BraincraftedBootstrapBundle:Menu:menu.html.twig"
The problem is that configuration is set globally, so when i try to use KnpMenu in the bundle that doesn't require bootstrap I get an error.
How can I set this specific configuration for one bundle only?
I believe you can specify the template you want when you call the knp_menu_render twig method in your layout:
{{ knp_menu_render('main', {'template': 'BraincraftedBootstrapBundle:Menu:menu.html.twig'}, 'custom') }}

Turn off escaping in Symfony 2 / twig

I'm creating a form using the form builder in Symfony. I am adding an attribute into the twig file for my checkboxes which contains an ampersand and pound sign, Symfony is automatically escaping the ampersand which stops it displaying correctly. Is there anyway to turn off escaping on a per case basis in either the twig file or the controller, or switch it off completely in the config?
{{ form_widget(form.checkbox, { 'attr': {'data-icon-checkmark': '󰀦', 'data-icon-checkmark-checked': '󰀧'} }) }}
I have found a few topics on this for 1.X versions of Symfony, but nothing for 2.
Thanks!
Probably what you need is the raw tag or filter. Also take a look at the autoescape tag.
To turn autoescaping off globally, set the autoescape option to false in config.yml:
twig:
# ...
autoescape: false
You can use |raw filter.
http://symfony.com/doc/current/book/templating.html#output-escaping-in-twig

Resources