Symfony2 translation in twig using CsvFileLoader - php

I want to implement translation in Symfony2 using csvFileLoader. In config.yml translation field is enabled and locale set to fr.
I have written following code in controller.
$file = //file path eg: messages.fr.csv;
$loader = new CsvFileLoader($file);
$loader->setCsvControl(',');
$x = $loader->load($file, 'fr');
$translator = new Translator('fr',new MessageSelector());
$translator->addLoader('csv', $loader);
$translator->addResource('csv', $file, 'fr','messages');
$translator->trans('Symfony is great');
Above code works fine. If I use trans tag in twig then text is not translated. Even I add twig extentions:-
$loader = new \Twig_Loader_Filesystem("path to twig template file");
$twig = new \Twig_Environment($loader);
$twig->addExtension(new TranslationExtension($translator));
And Code in witten in twig file
{% trans %}Symfony2 is great{% endtrans %}
Above text is not translated in twig. I tried it using .xlf file then it works but for .csv file translation is not working.
Need solution for above mentioned issue.

Controller :
/**
* #Route("{_locale}/translate1")
*/
public function showTwoAction(Request $request)
{
$delimiter = ";";
$enclosure = '"';
$escape = '\\';
$file = __DIR__.'/file_'.$request->getLocale().'.csv';
$translator = new Translator($request->getLocale(), new MessageSelector());
$translator->addLoader('csv', new CsvFileLoader());
$translator->addResource('csv', $file, $request->getLocale());
$catalogue = $translator->getCatalogue($request->getLocale());
$messages = $catalogue->all();
while ($catalogue = $catalogue->getFallbackCatalogue())
{
$messages = array_replace_recursive($catalogue->all(), $messages);
}
return $this->render("PRIYACoreTranslateBundle:Default:translate.html.twig",$messages);
}
Twig :
{{ messages.Hi }}
{{ messages.Hello }}
Translation CSV Files
=> file_en.csv
"Hi";"Hi"
"Hello";"Hello"
=> file_fr.csv
"Hi";"salut"
"Hello";"Bonjour"
Hope it helps.

Related

Translator component with twig trans

I am trying to have my twig templates translated using the Symfony Translator Component and .mo files. I used the i18n extention before but wanted a more reliable approach since locale handling for translations on Windows is a nightmare.
These class functions prepare the translation and template:
/**
* Constructor.
*
* #param string $template_dir
* #param string $locale
* #param string $locale_path
*/
public function __construct($template_dir, $locale, $locale_path)
{
$loader = new Twig_Loader_Filesystem($template_dir);
$this->parser = new TemplateNameParser();
$this->template = new \Twig_Environment($loader);
$this->translator = new Translator($locale);
$this->translator->addLoader('mo', new \Symfony\Component\Translation\Loader\MoFileLoader());
$this->translator->addResource('mo', $locale_path, $locale);
$this->template->addExtension(new TranslationExtension($this->translator));
}
/**
* Render template.
*/
public function render($name,$parameters=[]) {
return $this->template->loadTemplate($name,$parameters)->render();
}
Then i have this template:
<h1>{% trans 'Hello World!' %}</h1>
which throws this error:
Uncaught Twig_Error_Syntax: Unexpected token. Twig was looking for the
"with", "from", or "into" keyword.
Which i get because i am not adding the Twig_Extensions_Extension_I18n extension to twig environment. If i do that, the texts in trans functions are not translated because i am not using the filter as i should. For it to work i need to use the trans filter like so: {{ 'Some text'|trans }}.
Is there a way to make translation work with {% trans 'Some text' %} instead of {{ 'Some text'|trans }}? For example, can i add a custom trans function somewhere in the chain?
Note: I know that {% trans %}Some text{% endtrans %} works, but all my templates already use this syntax {% trans 'Some text' %}, and i would like to prevent having to rewrite everything.
The problem seems to stem from incompatible twig and symfony translator versions. But i am not sure tbh.
In my case, i solved the problem long-term by writing a simple script to replace the incorrect syntax with the correct one in each template file.
foreach (glob("your_template_path/*/*/*.twig") as $filename) {
$content = file_get_contents($filename);
$content = preg_replace_callback('/{% trans "[\s\S]+?" %}/',function($matches) {
$text = str_replace(['{% trans','%}','"'],'',$matches[0]);
return '{% trans %}'.trim($text).'{% endtrans %}';
},$content);
$content = preg_replace_callback('/{% trans \'[\s\S]+?\' %}/',function($matches) {
$text = str_replace(['{% trans','%}',"'"],'',$matches[0]);
return '{% trans %}'.trim($text).'{% endtrans %}';
},$content);
file_put_contents($filename,$content);
}
Maybe that helps someone.
Try this
"{% trans %}Hello World{% endtrans %}!"

How to add own translator loader/filetype/"logic" to Symfony 3

In my symfony project I want to add mulitple mail templates in my resources folder.
Filepath pattern:
app/Resources/translations/emails/[LOCALE]/[mail-type].html.twig
I've got my loader, named MailLoader witch load():
public function load($resource, $locale, $domain = 'messages')
{
$messages = [];
$label = strstr(basename($resource), '.', true);
$messages[$label] = file_get_contents($resource);
$catalogue = new MessageCatalogue($locale);
$catalogue->add($messages, $domain);
return $catalogue;
}
I want to use $translator->trans('mail-type'); to get specifc for locale content of file.
It's work when I do it like this:
$translator = new Translator('pl');
$translator->addLoader('mails', new MailLoader());
$finder = new Finder();
$finder->files()->in(__DIR__ . '/../Resources/views/email/pl');//->name('*.html.twig');
foreach ($finder as $file) {
$translator->addResource('mails', $file->getPath() . '/' . $file->getFilename(), 'pl');
}
echo $translator->trans('order-closed');//Returns file content.
But I want to extend Symfony Translator in container to use it everywhere I need. How to do it?
Please, I work wit this soo long. It's my first work with this Symfony Component and... It's made me crazy! >:D

how to create filter new in twig template in php

I want to add a new filter in twig template in php
For example
{{ "<h1>title</h1>"|raw}}
a new filter
{{ "<h1>title</h1>"|newfilter}}
And I don't want to use symfony
Simply use Twig_SimpleFilter.
// an anonymous function
$filter = new Twig_SimpleFilter('newfilter', function ($string) {
//do stuff
return $string;
});
$twig = new Twig_Environment($loader);
$twig->addFilter($filter);

How to check if a certain file already exists in symfony2?

I am working on symfony2 and currently I want to check if a file does exist. My scenario look something like this,, I have two files excel file and the docx file. If a person have an excel file for her/his transaction then it is automatically that the docx file is not applicable for her or him.And vice versa. How can I possibly do it in symfony2? A lot in the net but I don't know how to do it in my case,, thanks a lot :)
UPDATE
Controller:
public function documentType ($doc_type) {
$em = $this->getDoctrine()->getEntityManager();
$result = $em->getRepository('SupplierBundle:SupplierTransactionDetails')->findDocumentType('xlsx');
$result1 = $em->getRepository('SupplierBundle:SupplierTransactionDetails')->findDocumentType('docx');
// statement that will know if the file exists for that certain user if so the other document type will be not applicable for that user. Example: that user have docx file already then the xlsx will be N/A and vice versa
}
Repository :
public function findDocumentType ($doc_type) {
$em = $this->getEntityManager();
$query = $em->createQuery(
'SELECT a, b, c FROM SupplierBundle:SupplierTransaction Details a
JOIN a.supplierTransaction b
JOIN b.supplierDocType c
WHERE c.docType LIKE :doc_type'
)->setParameter('doc_type', $doc_type);
return $query->getResult();
}
You can just use plain PHP for this. For example:
$xls = 'sheet.xlsx';
$doc = 'document.docx';
if (file_exists($xls)) {
// User has an XLSX file
echo 'Download your sheet here.';
} elseif (file_exists($doc)) {
// User has a DOCX file
echo 'Download your document here.';
}
If you want to do it the Symfony2 way, you can use the Filesystem class, it has an exists() function. In a controller an instance is automatically available in the service container:
$em = $this->getDoctrine()->getManager();
$xlsx = $em->getRepository('SupplierBundle:SupplierTransactionDetail')->findDocumentType‌('xlsx');
$docx = $em->getRepository('SupplierBundle:SupplierTransactionDetail')->findDocumnetType‌('docx');
return [
'xlsx' => $xlsx instanceof SupplierTransactionDetail && $this->get('filesystem')->exists($xlsx->getFile()) ? $xlsx->getFile() : null,
'docx' => $docx instanceof SupplierTransactionDetail && $this->get('filesystem')->exists($docx->getFile()) ? $docx->getFile() : null,
];
In your twig template:
{% if xlsx is not empty %}
{{ xlsx }}
{% endif %}
{% if docx is not empty %}
{{ docx }}
{% endif %}

Read controllers custom annotations from a custom Command in Symfony 2

I have created custom annotations to generate JSON files (for NodeRed if you ask...) and i'm testing them successfully from a dummy method in a dummy controller.
I would like to port all that to a custom Sf command whose job would be to read all Controllers annotations in my bundle and achieve the same result (aka create JSON files).
How could i achieve that ? Would looping through XxxxController.php file(s) with the finder be a good option ? Or am too ambitious ? :p
Annotation example:
/**
* #NodeRedFlows(
* triggerBy="testFlow", options={"interval":"45"}
* )
*/
public function indexAction() { /*...*/ }
Sorry its not easy to post some more code because i have the whole reader class, the annotation class and another class creating JSON flows based on the triggerBy="testFlow" id.
Bottom line:*
I would like to be able to create my JSON flow file from a Command instead of here in my Controller (used it for tests).
Load all controller actions, which have been assigned a route in Symfony (see this and this).
Then load the annotations for every found controller action:
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\HttpFoundation\Request;
$annotationReader = new AnnotationReader();
$routes = $this->container->get('router')->getRouteCollection()->all();
$this->container->set('request', new Request(), 'request');
foreach ($routes as $route => $param) {
$defaults = $params->getDefaults();
if (isset($defaults['_controller'])) {
list($controllerService, $controllerMethod) = explode(':', $defaults['_controller']);
$controllerObject = $this->container->get($controllerService);
$reflectedMethod = new \ReflectionMethod($controllerObject, $controllerMethod);
// the annotations
$annotations = $annotationReader->getMethodAnnotations($reflectedMethod );
}
}
UPDATE:
If you need all controller methods, including those without the #Route annotation, then I would do what you suggest in your question:
// Load all registered bundles
$bundles = $this->container->getParameter('kernel.bundles');
foreach ($bundles as $name => $class) {
// Check these are really your bundles, not the vendor bundles
$bundlePrefix = 'MyBundle';
if (substr($name, 0, strlen($bundlePrefix)) != $bundlePrefix) continue;
$namespaceParts = explode('\\', $class);
// remove class name
array_pop($namespaceParts);
$bundleNamespace = implode('\\', $namespaceParts);
$rootPath = $this->container->get('kernel')->getRootDir().'/../src/';
$controllerDir = $rootPath.$bundleNamespace.'/Controller';
$files = scandir($controllerDir);
foreach ($files as $file) {
list($filename, $ext) = explode('.', $file);
if ($ext != 'php') continue;
$class = $bundleNamespace.'\\Controller\\'.$filename;
$reflectedClass = new \ReflectionClass($class);
foreach ($reflectedClass->getMethods() as $reflectedMethod) {
// the annotations
$annotations = $annotationReader->getMethodAnnotations($reflectedMethod);
}
}
}

Categories