6

I'm trying to build a language switcher into my main navigation, which is created by the KNPMenuBundle. Translations are done with the JMSTranslationBundle. Both work fine.

I want to create a language switcher with my menu builder, but the generation of the correct routes gives me some headaches.

This is my service:

class MenuService
{
    private $factory;
    private $translator;
    private $router;

    public function __construct(FactoryInterface $factory, Translator $translator, Router $router)
    {
        $this->factory = $factory;
        $this->translator = $translator;
        $this->router = $router;
    }

    public function createMainMenu(RequestStack $requestStack, array $languages)
    {
        // Language Switcher - $languages === ['en', 'de']
        $request = $requestStack->getCurrentRequest();
        $routeName = $request->get('_route');

        $menu->addChild('menu.language', array(
            'uri' => '#',
            'label' => '<i class=\'fa fa-flag-checkered\'></i> '.$this->translator->trans('menu.language.main'),
            'extras' => array('safe_label' => true)
        ))
            ->setAttribute('class', 'dropdown singleDrop')
            ->setChildrenAttribute('class', 'dropdown-menu dropdown-menu-left')
        ;

        foreach ($languages as $language)
        {
            $menu->getChild('menu.language')->addChild('menu.language.'.$language, array(
                'route' => $this->router->generate($routeName, array_merge($request->get('_route_params'), ['_locale' => $language]))
            ));
        }
    }

And this is my service definition

menu_builder:
    class: AppBundle\DependencyInjection\MenuService
    arguments: ['@knp_menu.factory', '@translator.default', '@jms_i18n_routing.router']

menu.main:
    class: Knp\Menu\MenuItem
    factory: ['@menu_builder', createMainMenu]
    arguments: ['@request_stack', '%locales%']
    scope: request
    tags:
      - { name: knp_menu.menu, alias: main }

If I inject the Router provided by the JMSTranslationBundle, I receive the following error:

An exception has been thrown during the rendering of a template ("Unable to generate a URL for the named route "/en/" as such route does not exist.").

If I'm using the default router of symfony I'm getting this error message:

An exception has been thrown during the rendering of a template ("Unable to generate a URL for the named route "homepage" as such route does not exist.").

When I debug the router on the console, this is the output:

  en__RG__homepage                                         ANY        ANY      ANY    /en/                                                 
  de__RG__homepage                                         ANY        ANY      ANY    /de/  

Which router must be used to get the routing to work?

Alain Tiemblo
  • 36,099
  • 17
  • 121
  • 153
KhorneHoly
  • 4,666
  • 6
  • 43
  • 75
  • where does `$routeName` in `'route' => $this->router->generate($routeName, array_merge($request->get('_route_params'), ['_locale' => $language]))` comes from? – lordrhodos Jun 20 '17 at 12:32
  • @lordrhodos I've edited my question, I've forgot that part, thank you for pointing it out. – KhorneHoly Jun 20 '17 at 12:40
  • 1
    I think you must use : JMS\I18nRoutingBundle\Router, see https://github.com/schmittjoh/JMSI18nRoutingBundle/blob/master/Router/I18nRouter.php Hope this helps ! – Weenesta - Mathieu Dormeval Jun 24 '17 at 06:18
  • @MathieuDormeval thank you for your reply. Truly, I must use the Router from the JMS Routing Bundle, but that didn't fix the issue. – KhorneHoly Jun 26 '17 at 09:54

1 Answers1

0

I've found my mistake with the usage of those two bundles.

The JMS\I18nRoutingBundle\Router::generate() function will return the absolute path for the route given to the function.

So the following happens:

$absolutePath = $this->router->generate('homepage', array_merge($request->get('_route_params'), ['_locale' => $language]));
dump($absolutePath); // Will return "/de/" or "/en" in my case

So, taken that into account, my generation of the routes with the parameter route will obviously fail, because the function doesn't return the route but the absolute path.

Given that, this works:

foreach ($languages as $language)
{
    $menu->getChild('menu.language')->addChild('menu.language.'.$language, array(
        'uri' => $this->router->generate($routeName, array_merge($request->get('_route_params'), ['_locale' => $language]))
    ));
}

If I change the route to uri my code works correctly.

KhorneHoly
  • 4,666
  • 6
  • 43
  • 75