Nebular: Use translation for menuItems

Created on 13 Nov 2017  路  11Comments  路  Source: akveo/nebular

Hi,
I'm using this theme in my Angluar Projekt.
I need to translate the title of the menuItems depending on the current language of my application.
Is there a possibility to do this?
I'm use ngx-translate for translation in my project.

important enhancement theme needs docs

Most helpful comment

thanks for your reply and idea. works!

export class PagesComponent implements OnInit {
  menu: NbMenuItem[];

  constructor( private translate: TranslateService ) {
    this.menu = MENU_ITEMS;
  }

  ngOnInit() {
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      this.translateMenuItems();
    });
    this.translateMenuItems();
  }

  translateMenuItems() {
    this.menu.forEach( item => {
      this.translateMenuItem( item );
    });
  }

  translateMenuItem( menuItem: NbMenuItem ) {
    if ( menuItem.children != null ) {
      menuItem.children.forEach( item => this.translateMenuItem( item ) );
    }

    if(menuItem.data === undefined) {
      menuItem.data = menuItem.title;
      menuItem.title = this.translate.instant( menuItem.title );
    } else {
      menuItem.title = this.translate.instant( menuItem.data );
    }
  }
}

All 11 comments

Hi @SebastianFreund, take a look at https://github.com/akveo/ngx-admin/issues/1305. Hopefully, this helps.

Hi @nnixaa!
Yes, it helps me but it didn't solve the whole problem.
I have implemented the descripted solution, but if the language changes, the menuItems will not be translated again.
Any ideas how I can solve this problem?

@SebastianFreund did you look at the NBMenuInternalService? There is a reset items. not sure if this will help but maybe after a translate, reset the menu? I agree we should be able to pass a pipe into nebular components to make it easier for the switch to be more native, then having to call a function.... Maybe a feature improvement can be made @nnixaa

@blankstar85 Thank you for your help! I haven't seen the NbMenuInternalService before, but your solution works for me. But I agree with you, to pass a pipe into the components would it make much easier!
The only problem I still have: After reseting the menu, no menuItem is selected and I don't know how to select the menuItem which was selected before the reset. I have tried itemSelect() from NbMenuInternalService, but this didn't work.

I decided to go a different way than the solution proposed in https://github.com/akveo/ngx-admin/issues/1305

In my pages.component.ts, I iterate on every menu item and change only the title of each element.

I also subscribed to the onLangChange event and simply re-translate the titles from there. No need to ever reset the menu items.

I created a gist for this. Please feel free to leave me comments.

Great solution @dizco !
My problem was, that i writed the translation-string in the title field. In this way i had to clone the MENU_ITEMS object, that i don't overwrite the translation-string when i translate the title. -> Through the clone I lost the object-reference on retranslate an so i need to reset the menu.
Now i store the translation-string in the data field (like @dizco in the key field) and now there is no need to reset the menu. Every thing works fine.
This is my code from pages.component.ts:

    menu: NbMenuItem[];

    constructor( private translateService: TranslateService ) { }

    ngOnInit()
    {
        this.menu = MENU_ITEMS;
        this.translateService.onLangChange.subscribe( event => this.translateMenuItems() );
        this.translateMenuItems();
    }

    translateMenuItems()
    {
        this.menu.forEach( item => this.translateMenuItem( item ) );
    }

    translateMenuItem( menuItem: NbMenuItem )
    {
        if ( menuItem.children != null )
        {
            menuItem.children.forEach( item => this.translateMenuItem( item ) );
        }
        menuItem.title = this.translateService.instant( menuItem.data );
    }

@SebastianFreund ah yes I faced that issue too, seems like we have some very similar solutions :)

@SebastianFreund on your solution the translation works only once because the title is translated and no translation key is available

one option is to copy the object?

menu: NbMenuItem[];
  save_menu: NbMenuItem[];

  constructor( private translate: TranslateService ) {
    this.menu = MENU_ITEMS;
    this.save_menu = JSON.parse(JSON.stringify(MENU_ITEMS))
  }

  ngOnInit() {
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      this.menu = this.save_menu;
      this.save_menu = JSON.parse(JSON.stringify(this.save_menu));
      this.translateMenuItems();
    });

    this.translateMenuItems();
  }

  translateMenuItems() {
    this.menu.forEach( item => {
      this.translateMenuItem( item );
    });
  }

  translateMenuItem( menuItem: NbMenuItem ) {
    if ( menuItem.children != null ) {
      menuItem.children.forEach( item => this.translateMenuItem( item ) );
    }
    menuItem.title = this.translate.instant( menuItem.title );
  }
}

This was my first solution. But you have to reset the menu with this solution, and then you lose the selection of the current selected page. Now i store the translation key in the data-field of the menu-item. Then there is no need to copy the object.

thanks for your reply and idea. works!

export class PagesComponent implements OnInit {
  menu: NbMenuItem[];

  constructor( private translate: TranslateService ) {
    this.menu = MENU_ITEMS;
  }

  ngOnInit() {
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      this.translateMenuItems();
    });
    this.translateMenuItems();
  }

  translateMenuItems() {
    this.menu.forEach( item => {
      this.translateMenuItem( item );
    });
  }

  translateMenuItem( menuItem: NbMenuItem ) {
    if ( menuItem.children != null ) {
      menuItem.children.forEach( item => this.translateMenuItem( item ) );
    }

    if(menuItem.data === undefined) {
      menuItem.data = menuItem.title;
      menuItem.title = this.translate.instant( menuItem.title );
    } else {
      menuItem.title = this.translate.instant( menuItem.data );
    }
  }
}

My working example:

 export class SidebarComponent implements OnInit {
   menu: NbMenuItem[];

   constructor( private translate: TranslateService ) {}

  ngOnInit() {
    this.menu = MENU_ITEMS;
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      this.translateMenuItems();
    });
    this.translateMenuItems();
  }

  translateMenuItems() {
    this.menu.forEach((item: NbMenuItem) => {
      this.translateMenuItem(item);
    });
  }

  translateMenuItem( menuItem: NbMenuItem ) {
    if ( menuItem.children != null ) {
      menuItem.children.forEach((item: NbMenuItem) => this.translateMenuItem(item) );
    }

    if (menuItem.data === undefined) {
      menuItem.data = menuItem.title;
      this.getTranslation(menuItem, menuItem.title);
    } else {
      this.getTranslation(menuItem, menuItem.data);
    }
  }

  getTranslation(item: NbMenuItem, key: string) {
    const k = `sidebar.${key.toLowerCase()}`;
    this.translate.get(k).subscribe((translation: string) => {
      item.title = translation;
    });
  }
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

suku-h picture suku-h  路  3Comments

aqsdc1 picture aqsdc1  路  3Comments

bnbs picture bnbs  路  4Comments

obarazan picture obarazan  路  3Comments

johnsnow20087349 picture johnsnow20087349  路  3Comments