0

Introduction

In my personal project I am using:

  • XAMPP with PHP v7.1.6
  • Symfony v3.3.6
  • KnpMnenuBundle dev-master / 2.2.x-dev [link 1], [link 2], [link 3] in order to manage Menus.
  • Bootstrap v3.3.7
  • Bootstrap and KnpMenuBundle integration [link 4]

Setting up

To setup i used documentation in [2], [3] and code samples [4]. My menu is working, integration between Bootstrap and KnpMenuBundle also works.

At the moment

Menu bundle works fine, simple translating works and integration works too.

My ProfileMenu code sample:

public function profileMenu(array $options)
{
    $menu = $this->factory->createItem('root');
    $menu->setChildrenAttribute('class', 'nav navbar-nav navbar-right');

    $menu->addChild('Profile', array('label' => 'menu.profile'))
        ->setExtras(array('dropdown' => true, 'icon' => 'fa fa-user'))
        ->setLinkAttribute('class', "dropdown-toggle")
        ->setLinkAttribute('data-toggle', "dropdown")
        ->setExtra('translation_domain', 'menu');

    $menu['Profile']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('Logged in as', array('label' => 'layout.logged_in_as'))
        ->setExtra('divider_append', true)
        ->setExtra('translation_domain', 'FOSUserBundle');

    $menu['Profile']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('My data', array('label' => 'menu.profile.myData', 'route' => 'fos_user_profile_show'))
        ->setExtra('translation_domain', 'menu');
    $menu['Profile']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('Edit data', array('label' => 'menu.profile.editMyData', 'route' => 'fos_user_profile_edit'))
        ->setExtra('translation_domain', 'menu');
    $menu['Profile']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('Change password', array('label' => 'menu.profile.changePassword', 'route' => 'fos_user_change_password'))
        ->setExtra('translation_domain', 'menu');

    $menu['Profile']->setChildrenAttribute("class", "dropdown-menu")
        ->addChild('Exit', array('label' => 'menu.profile.logout', 'route' => 'fos_user_security_logout'))
        ->setExtra('divider_prepend', true)
        ->setExtra('translation_domain', 'menu');

    return $menu;
}

menu rendering is shown in following image

menu rendering

Question

How can i pass translation parameters (namely %username%) to menu (powered by KnpMenuBundle) and get it to render as intended?

How can one supply arguments:

|trans({'%username%': app.user.username}

in the MenuBuilder?

MY CODE

The code block in question is

$menu['Profile']->setChildrenAttribute("class", "dropdown-menu")
    ->addChild('Logged in as', array('label' => 'layout.logged_in_as'))
    ->setExtra('divider_append', true)
    ->setExtra('translation_domain', 'FOSUserBundle');

namely label string

Translating strings with parameters ordinarily, one would supply arguments like so:

<li><a href="#">{{ 'layout.logged_in_as'|trans({'%username%': app.user.username}, 'FOSUserBundle') }}</a></li>

Yet, i can not seem to figure out how to pass them in case of using KnpMenuBundle and Bootstrap integration.

Conclusion

Please advise.

Thank you for your time and knowledge.

Rikijs
  • 728
  • 1
  • 12
  • 48

3 Answers3

2

You could declare your MenuBuilder as a service like this

#services.yml
app.menu_builder:
        class: AppBundle\Menu\MenuBuilder
        arguments:
            - @knp_menu.factory
            - @security.token_storage
            - @translator.default

Update MenuBuilder's constructor according to the dependencies on the above definition

With this you have access to all the things you need to perform your traduction

$user = $this->tokenStorage->getToken()->getUser(); // If you are under a path protect by security.yml access_constrol
$yourLoggedInTraduction = $this->translator->trans(
    'layout.logged_in_as', [
        '%username%' => $user->getUsername()
    ], 
    'FOSUserBundle', 
    'yourlocale'
); 
dump($yourLoggedInTraduction);

You should have your traduction and then map it to your profileMenu(...) function logic

I don't use sames version of symfony/knpMenu than you so maybe this code won't work directly but you just have to adapt to your needs

Ask for question if you want if it isn't clear

I hope I have helped you, if yes please mark the post as resolved ! : )

Mcsky
  • 1,426
  • 1
  • 10
  • 20
1

A specific option extras.translation_params is available but not documented: https://github.com/KnpLabs/KnpMenuBundle/blob/master/src/Resources/views/menu.html.twig#L7

You can use it in the same way you used the translation_domain option:

$menu['Profile']->setChildrenAttribute("class", "dropdown-menu")
    ->addChild('Logged in as', array('label' => 'layout.logged_in_as'))
    ->setExtra('divider_append', true)
    ->setExtra('translation_domain', 'FOSUserBundle')
    ->setExtra('translation_params', ['%username%' => $user->getUsername()]);
Seb33300
  • 7,464
  • 2
  • 40
  • 57
0

Simple answer to your question

Simply translate the label passed to addChild:

$label = $this->translator->trans('layout.logged_in_as', ['%user%' => $username ]);
$menu->addChild('Logged in as', array('label' => $label);

$this->translator is a \Symfony\Component\Translation\TranslatorInterface that is injected into the service creating the menu. I got it by passing "@translator" as an argument to the constructor in services.yml.

Add multiple child menus

For the sake of completeness, I'll also note that every child menu must have a different name. So, if you want to create multiple menus with different parameters, make sure you don't copy/paste the first line without also changing the menu name.

Or use something like this:

$idx = 0;
$menu->addChild("Language_".$idx++, array('label' => $label_lang1);
$menu->addChild("Language_".$idx++, array('label' => $label_lang2);

Or, if all the child menus are generated in one file:

$menu->addChild("Language_".__LINE__, array('label' => $label_lang1);
$menu->addChild("Language_".__LINE__, array('label' => $label_lang2);

If you don't use different names, only the last menu is displayed.

Avoid missing translation warnings

With the above solution, the symfony toolbar and the log both report warnings about missing messages. That's because the provided label can't be found in the translation domain (in messages.yml or whatever you use for your translations).

To avoid those false positive, add the following line after the addChild call:

$menu->addChild('Logged in as', array('label' => $label)
     ->setExtra('translation_domain', false);