Is is possible to have symfony2 log missing translation strings so that I know what needs adding to my xilff files? - symfony

I have a symfony project in which I've been through my twig templates and added {% trans %}...{% endtrans %} or adding translations like {{ title|trans }} where appropriate. I've also added a messages.de.xliff file and that is working perfectly for the few translations I have tried.
Is there a way I can get a list of strings missing from my xliff file? It's quite hard to keep track of every translation as I add it. It seems like it should log a failure to get a translation in a log file somewhere, but I've been googling a while and can't find anything.

Hi Try following May Be helpful.
https://github.com/schmittjoh/JMSTranslationBundle/blob/master/Resources/doc/index.rst
Very powerful tool and definitely takes care of you problem.

This is a very crappy patch to apply in vendor/symfony that does what I need. Probably not to be run on a production server!
diff --git a/src/Symfony/Component/Translation/MessageCatalogue.php b/src/Symfony/Component/Translation/MessageCatalogue.php
index b55676f..98a5cba 100644
--- a/src/Symfony/Component/Translation/MessageCatalogue.php
+++ b/src/Symfony/Component/Translation/MessageCatalogue.php
## -128,6 +128,8 ## class MessageCatalogue implements MessageCatalogueInterface
return $this->fallbackCatalogue->get($id, $domain);
}
+ error_log('Translation not found: "' . $id . '"');
+
return $id;
}

My solution was to overwrite the Translator and MessageCatalogue classes.
Translator:
class RegisteringTranslator extends \Symfony\Component\Translation\Translator
{
protected function loadCatalogue($locale)
{
parent::loadCatalogue($locale);
if ( ! $this->catalogues[$locale] instanceof RegisteringMessageCatalogue) {
$registeringCatalogue = new RegisteringMessageCatalogue($locale);
$registeringCatalogue->addCatalogue($this->catalogues[$locale]);
$this->catalogues[$locale] = $registeringCatalogue;
}
}
}
Catalogue:
class RegisteringMessageCatalogue extends \Symfony\Component\Translation\MessageCatalogue
{
public function get($id, $domain = 'messages')
{
if ( ! $this->has($id, $domain)) {
error_log('Translation not found: "' . $id . '"');
}
return parent::get($id, $domain);
}
}
Of course you need to use the new Translator class.
Also not very nice because it uses the protected methods and properties of Translator class. But better than changing the Symfony code directly.

I know this is an old question, but I'm posting here just in case somebody still has the same problem.
Starting from Symfony 2.6, you'll find a very nice addition to the web debug toolbar that shows how many translations you're missing.
By clicking it, the profiler will display a detailed list of missing translation.
Works out of the box, without any configuration.

Normally you should be able to use the Symfony command debug:translation via app/console.
Something like this:
$ php app/console debug:translation --only-missing <locale> <Bundle Name>
A concrete example would be:
$ php app/console debug:translation --only-missing nl AppBundle
That would output:
----------- ---------- ------------------------------------------------------------------------------------------------------- ------------------------------------------
State Domain Id Message Preview (nl)
----------- ---------- ------------------------------------------------------------------------------------------------------- ------------------------------------------
missing messages Create a clean selection Create a clean selection
missing messages New Selection New Selection
missing messages login.labels.geoserver_url login.labels.geoserver_url

Related

Trying to add social media links to Drupal website

I'm trying to add social media icons to my drupal website and followed this guide to try and install them. The module seems to install fine, however when I try to configure it to add different links on clicking save it brings me to a webpage that simply says The website encountered an unexpected error. Please try again later.
I've tried uninstalling/reinstalling the plugin and that didn't seem to do anything. Are there some permissions I'm missing in my set up? I'm pretty much brand new to drupal
Edit: The url of the error is admin/structure/block/manage/socialmedialinks?destination=/node
and some of the error log:
TypeError: Argument 2 passed to Egulias\EmailValidator\EmailValidator::isValid() must implement interface Egulias\EmailValidator\Validation\EmailValidation, bool given,
It seems the social_media_links drupal module version 8.x-2.6 has a bug when it checks the validity of email addresses.
There is an issue in the module's issue queue for it HERE.
There is a patch attached to the issue (attached below):
diff --git a/src/Plugin/SocialMediaLinks/Platform/Email.php b/src/Plugin/SocialMediaLinks/Platform/Email.php
index 007e59f..2926d47 100755
--- a/src/Plugin/SocialMediaLinks/Platform/Email.php
+++ b/src/Plugin/SocialMediaLinks/Platform/Email.php
## -4,7 +4,6 ## namespace Drupal\social_media_links\Plugin\SocialMediaLinks\Platform;
use Drupal\social_media_links\PlatformBase;
use Drupal\Core\Form\FormStateInterface;
-use Egulias\EmailValidator\EmailValidator;
use Drupal\Core\Url;
/**
## -29,9 +28,9 ## class Email extends PlatformBase {
*/
public static function validateValue(array &$element, FormStateInterface $form_state, array $form) {
if (!empty($element['#value'])) {
- $validator = new EmailValidator();
+ $validator = \Drupal::service('email.validator');
- if (!$validator->isValid($element['#value'], TRUE)) {
+ if (!$validator->isValid($element['#value'])) {
$form_state->setError($element, t('The entered email address is not valid.'));
}
}

Symfony2 error : Case mismatch between loaded and declared class names:

I'm working on Symfony2 and i updated my project with composer.phar update
Now, when i check my site with app_dev.php i always have this error :
Case mismatch between loaded and declared class names: Blu\ProjectBun
dle\Entity\AccountRepository vs Blu\ProjectBundle\Entity\AccountRepos
itory
It's the same when i clear the dev cache, manually or not. I have nothing special in AccountRepository.php..
Any ideas ?
Edit : I already tried to add if ($name !== $class && 0 === strcasecmp($name, $class)) { in DebugClassLoader.php and no effect
Intent to var_dump($name) and var_dump($class) and strcasecmp($name, $class) to see why you enter in the condition.
though the answer was a typo in the class namespace, this errors occurs also if your entity is defined via xml, i.e. User.orm.xml, and you accidentally name the file lower-case, this will drive nuts the xml loader
create FooNamespace\BarBundle\Resources\config\User.orm.xml
create FooNamespace\BarBundle\Entity\User.php (class User { ... })
I had this problem and after trying all the solutions I found, no one of them worked for me. I am working with Symfony 2.8, Doctrine ORM and Sonata Admin Bundle and this exception appeared when I added an admin class (for a class related with the class showed in the exception message) and I tried to open it.
My mistake was I wrote the name of the database tables in lowercase in Doctrine annotations in the class related, check if you have it in uppercase:
ORM\ManyToOne(targetEntity="Product")
This is a known bug in Symfony2 :
https://github.com/symfony/symfony/commit/8e9cc35
It has been merged in 2.5 but not tagged yet (source)
To check if this is really the case for you, you might want to try modifying the src/Symfony/Component/Debug/DebugClassLoader.php file manually :
// Line 178
if ($name !== $class && 0 === strcasecmp($name, $class)) {
... and check if you still have the problem after clearing your cache
Please Add this if condition in DebugClassLoader.php File at line 177
if ($name === $class) {
if ($name !== $class && 0 === strcasecmp($name, $class)) {
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: %s vs %s', $class, $name));
}
}
It will solve your problem
Location: root\Projectname\Symfony\vendor\symfony\symfony\src\Symfony\Component\Debug
thanks
Your controller name first word is lowercase in your routing.yml
usr_teacher_new:
path: /new
defaults: { _controller: CoreUserBundle:teacher:newteacher }
like teacher..
will be Teacher

php - Is php caching classes before creation?

Background Information:
I'm using Symfony Console Component to write a console application that is wrapped into a Shell object. I wrote a command named console:reload that empties the array of commands from the Application object, and re-adds commands classes listed under certain directory.
This command is run when the shell starts, so, the Application is loaded with the available commands. The classes being loaded are located in a special directory and should follow a simple name rule: <CommandName>Command.php:
// Inside ReloadCommand->execute() method...
$pamperoApp = $this->getApplication();
$pamperoApp->clearCommands();
$namespace = "pampero\\cli\\modules";
foreach(glob(MODULES_DIR . "/*/*Command.php") as $command) {
$class = str_replace(".php", "", $namespace . "\\" . basename(dirname($command)) . "\\" . basename($command));
$this->getApplication()->add(new $class);
}
The autoload provided by Symfony (Composer?) ClassLoader is used:
// Main entry point...
loader = require_once __DIR__ . '/../vendor/autoload.php';
$loader->set('pampero', __DIR__ . '/../..');
I read the code from ClassLoader class and what it does is to store file name path, so no object caching there.
Here's the problem:
I launch the app: php packages.php. The shell appears after ReloadCommand command being executed. A list of available and loaded commands are ready to be used.
If I create a new file, let's say: ExampleCommand.php, and then I type: console:reload, the new command will indeed be added. Now, If I modify the code inside ExampleCommand.php and run console:reload again, the changes made to the class won't take effect.
But that's not all. If I remove the example file, call console:reload, create the file again and run: console:reload the command will be added.
Reading:
I have read APC related things, and before creating new classes I have done things like:
// Prior adding commands in ReloadCommand
apc_clear_cache();
apc_clear_cache('user');
apc_clear_cache('opcode');
Without luck. I've also run apc.php and enabled/disabled apc.enable_cli option. None of those things creates the object represented by the modified file.
So my hints and clues about the problems turns to be classes caching when a file/class is found. But how to avoid that for this special case? I don't want to restart the shell if some extra funcionality is added through classes.
Any ideas?
I will answer my own question as I found a solution.
Ok, clues were fine. The problem was that PHP including a file binds the symbols for later use while parsing the file.
So, I needed some kind of instrospection. After reading/googling/searching for all night, finally I've ended up finding Runkit.
Runkit documentation can be found here. I know that is not the best thing you can do with your code design. But for my project needs, the truth is that Reflection was needed.
Here is the modified code using Runkit:
protected function execute(InputInterface $input, OutputInterface $output)
{
// Gets a reference to the console application and removes all commands
$pamperoApp = $this->getApplication();
$pamperoApp->clearCommands();
// Adds default commands and add this command
$pamperoApp->addCommands($pamperoApp->getDefaultCommands());
$pamperoApp->add($this);
$namespace = "pampero\\cli\\modules";
foreach(glob(MODULES_DIR . "/*/*Command.php") as $filename) {
$className = str_replace(".php", "", $namespace . "\\" . basename(dirname($filename)) . "\\" . basename($filename));
// Do not add this command again. This command shouldn't be modified on-the-fly
if (get_class($this) !== $className) {
$class = new $className();
// Redefines the class definition
runkit_import($filename, RUNKIT_IMPORT_CLASSES | RUNKIT_OVERRIDE_OBJECTS | RUNKIT_IMPORT_OVERRIDE);
$pamperoApp->add($class);
}
}
}

Custom route configuration with Silex

I know that the basis of Silex approach in which all the application logic in a single file. But my application will be possible to have more than twenty controllers. So I want to have a handy map to manage the router.
My question is to search for solutions in which I would be able to make a router to a separate file. In the best case, the file must be of YAML type:
# config/routing.yml
_home:
pattern: /
defaults: { _controller: MyProject\Controller\MyController::index }
But the native is also a good case (for me):
$routes = new RouteCollection();
$routes->add(
'home',
new Route('/', array('controller' => 'MyProject\Controller\MyController::index')
));
return $routes;
Problem of the second case is that I have to use the match() function for each rule of routing. It is not at all clear.
What are the ways to solve this issue? The condition is that I want to use the existing API Silex or components of Symfony2.
Small note:
I don't use a ControllerProviderInterface for my Controller classes. This is an independent classes.
First of all, the basis of Silex is not that you put everything in one file. The basis of Silex is that you create your own 'framework', your own way of organizing applications.
"Use silex if you are comfortable with making all of your own architecture decisions and full stack Symfony2 if not."
-- Dustin Whittle
Read more about this in this blogpost, created by the creator of Silex.
How to solve your problem
What you basically want is to parse a Yaml file and get the pattern and defaults._controller settings from each route that is parsed.
To parse a Yaml file, you can use the Yaml Component of Symfony2. You get an array back which you can use to add the route to Silex:
// parse the yaml file
$routes = ...;
$app = new Silex\Application();
foreach ($routes as $route) {
$app->match($route['pattern'], $route['defaults']['_controller']);
}
// ...
$app->run();
I thought I'd add my method here as, although others may work, there isn't really a simple solution. Adding FileLocator / YamlFileLoader adds a load of bulk that I don't want in my application just to read / parse a yaml file.
Composer
First, you're going to need to include the relevant files. The symfony YAML component, and a really simple and useful config service provider by someone who actively works on Silex.
"require": {
"symfony/yaml": "~2.3",
"igorw/config-service-provider": "1.2.*"
}
File
Let's say that your routes file looks like this (routes.yml):
config.routes:
dashboard:
pattern: /
defaults: { _controller: 'IndexController::indexAction' }
method: GET
Registration
Individually register each yaml file. The first key in the file is the name it will be available under your $app variable (handled by the pimple service locator).
$this->register(new ConfigServiceProvider(__DIR__."/../config/services.yml"));
$this->register(new ConfigServiceProvider(__DIR__."/../config/routes.yml"));
// any more yaml files you like
Routes
You can get these routes using the following:
$routes = $app['config.routes']; // See the first key in the yaml file for this name
foreach ($routes as $name => $route)
{
$app->match($route['pattern'], $route['defaults']['_controller'])->bind($name)->method(isset($route['method'])?$route['method']:'GET');
}
->bind() allows you to 'name' your urls to be used within twig, for example.
->method() allows you to specify POST | GET. You'll note that I defaulted it to 'GET' with a ternary there if the route doesn't specify a method.
Ok, that's how I solved it.
This method is part of my application and called before run():
# /src/Application.php
...
protected function _initRoutes()
{
$locator = new FileLocator(__DIR__.'/config');
$loader = new YamlFileLoader($locator);
$this['routes'] = $loader->load('routes.yml');
}
Application class is my own and it extends Silex\Application.
Configuration file:
# /src/config/routes.yml
home:
pattern: /
defaults: { _controller: '\MyDemoSite\Controllers\DefaultController::indexAction' }
It works fine for me!
UPD:
I think this is the right option to add collections:
$this['routes']->addCollection($loader->load('routes.yml'));
More flexible.
You could extend the routes service (which is a RouteCollection), and load a YAML file with FileLocator and YamlFileLoader:
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
$app->extend('routes', function($routeCollection) {
$locator = new FileLocator([__DIR__ . '/../config']);
$loader = new YamlFileLoader($locator);
$collection = $loader->load('routes.yml');
$routeCollection->addCollection($collection);
return $routeCollection;
});
You will need symfony/config and symfony/yaml dependencies though.

Can I include an optional config file in Symfony2?

I want to make a local config file, config_local.yml, that allows each development environment to be configured correctly without screwing up other people's dev environments. I want it to be a separate file so that I can "gitignore" it and know that nothing essential is missing from the project, while simultaneously not having the issue of git constantly telling me that config_dev.yml has new changes (and running the risk of someone committing those changes).
Right now, I have config_dev.yml doing
imports:
- { resource: config_local.yml }
which is great, unless the file doesn't exist (i.e. for a new clone of the repository).
My question is: Is there any way to make this include optional? I.e., If the file exists then import it, otherwise ignore it.
Edit: I was hoping for a syntax like:
imports:
- { resource: config.yml }
? { resource: config_local.yml }
I know this is a really old question, and I do think the approved solution is better I thought I would give a simpler solution which has the benefit of not changing any code
You can use the ignore_errors option, which won't display any errors if the file doesn't exist
imports:
- { resource: config_local.yml, ignore_errors: true }
Warning, if you DO have a syntax error in the file, it will also be ignored, so if you have unexpected results, check to make sure there is no syntax error or other error in the file.
There is another option.
on app/appKernel.php change the registerContainerConfiguration method to this :
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
$extrafiles = array (
__DIR__.'/config/config_local.yml',
);
foreach ($extrafiles as $filename) {
if (file_exists($filename) && is_readable($filename)) {
$loader->load($filename);
}
}
}
this way you have a global config_local.yml file that overwrites the config_env.yml files
A solution is to create a separate environment, which is explained in the Symfony2 cookbook. If you do not wish to create one, there is another way involving the creation of an extension.
// src/Acme/Bundle/AcmeDemo/DepencendyInjection/AcmeDemoExtension.php
namespace Acme\DemoBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
class AcmeDemoExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
// All following files will be loaded from the configuration directory
// of your bundle. You may change the location to /app/ of course.
$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
try
{
$loader->load('config_local.yml');
}
catch(\InvalidArgumentException $e)
{
// File was not found
}
}
}
Some digging in the Symfony code revealed me that YamlFileLoader::load() FileLocator::locate() will throw \InvalidArgumentException, if a file is not found. It is invoked by YamlFileLoader::load().
If you use the naming conventions, the extension will be automatically executed. For a more thorough explanation, visit this blog.
I tried both above answers but none did work for me.
i made a new environment: "local" that imports "dev", but as you can read here: There is no extension able to load the configuration for "web_profiler" you also had to hack the AppKernel class.
Further you couldnt set config_local.yml to .gitignore because the file is necessary in local env.
Since i had to hack the AppKernel anyway i tried the approach with the $extrafiles but that resulted in "ForbiddenOverwriteException"
So now what worked for me was a modification of the $extrafiles approach:
replace in app/AppKernel.php
$loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml');
with
if ($this->getEnvironment() == 'dev') {
$extrafiles = array(
__DIR__ . '/config/config_local.yml',
);
foreach ($extrafiles as $filename) {
if (file_exists($filename) && is_readable($filename)) {
$loader->load($filename);
}
}
} else {
$loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml');
}

Resources