Skip to content

Instantly share code, notes, and snippets.

@dizco
Last active December 31, 2021 06:13
Show Gist options
  • Save dizco/0182af54fa90e9b1e4d7751c60a2a787 to your computer and use it in GitHub Desktop.
Save dizco/0182af54fa90e9b1e4d7751c60a2a787 to your computer and use it in GitHub Desktop.
Ngx-Admin and Nebular menu translation. Supports nested menu items and live reload
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
import { Component, OnInit } from '@angular/core';
import { AnalyticsService } from './@core/utils/analytics.service';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'ngx-app',
template: '<router-outlet></router-outlet>',
})
export class AppComponent implements OnInit {
constructor(private analytics: AnalyticsService, private translate: TranslateService) {
}
ngOnInit(): void {
this.analytics.trackPageViews();
this.translate.addLangs(['en', 'fr']);
this.translate.setDefaultLang('en');
this.translate.use(this.translate.getBrowserLang());
}
}
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
import { APP_BASE_HREF } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { CoreModule } from './@core/core.module';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { ThemeModule } from './@theme/theme.module';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http);
}
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpModule,
AppRoutingModule,
NgbModule.forRoot(),
ThemeModule.forRoot(),
CoreModule.forRoot(),
TranslateModule.forRoot({loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
}}),
],
bootstrap: [AppComponent],
providers: [
{ provide: APP_BASE_HREF, useValue: '/' },
],
})
export class AppModule {
}
{
"menu": {
"dashboard": "Dashboard",
"staff": {
"staff": "Staff",
"list": "List",
},
"users": "Users",
"settings": "Settings"
}
}
{
"menu": {
"dashboard": "Panneau",
"staff": {
"staff": "Staff",
"list": "Liste",
},
"users": "Utilisateurs",
"settings": "Paramètres"
}
}
import { NbMenuItem } from '@nebular/theme';
export declare abstract class MenuItem extends NbMenuItem {
key?: string;
children?: MenuItem[];
parent?: MenuItem;
}
import { MenuItem } from './menu-item';
export const MENU_ITEMS: MenuItem[] = [
{
title: 'Dashboard',
icon: 'fa fa-home',
link: '/pages/dashboard',
home: true,
key: 'dashboard',
},
{
title: 'Staff',
icon: 'ion-person-stalker',
link: '/pages/staff',
key: 'staff',
children: [
{
title: 'List',
link: '/pages/staff/list',
key: 'list',
},
],
},
{
title: 'Users',
icon: 'fa fa-users',
link: '/pages/users',
key: 'users',
},
{
title: 'Settings',
icon: 'ion-ios-gear-outline',
link: '/pages/settings',
key: 'settings',
},
];
import { Component, OnInit } from '@angular/core';
import { MENU_ITEMS } from './pages-menu';
import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
import { MenuItem } from '../@theme/custom-nebular/menu-item';
@Component({
selector: 'ngx-pages',
template: `
<ngx-sample-layout>
<nb-menu [items]="menu"></nb-menu>
<router-outlet></router-outlet>
</ngx-sample-layout>
`,
})
export class PagesComponent implements OnInit {
public menu = [];
constructor(private translate: TranslateService) {}
ngOnInit() {
this.menu = MENU_ITEMS;
this.translateMenu();
this.translate.onLangChange.subscribe((event: LangChangeEvent) => { //Live reload
this.translateMenu();
});
}
private translateMenu(): void {
this.menu.forEach((menuItem: MenuItem) => {
this.translateMenuTitle(menuItem);
});
}
/**
* Translates one root menu item and every nested children
* @param menuItem
* @param prefix
*/
private translateMenuTitle(menuItem: MenuItem, prefix: string = ''): void {
let key = '';
try {
key = (prefix !== '')
? PagesComponent.getMenuItemKey(menuItem, prefix)
: PagesComponent.getMenuItemKey(menuItem);
}
catch (e) {
//Key not found, don't change the menu item
return;
}
this.translate.get(key).subscribe((translation: string) => {
menuItem.title = translation;
});
if (menuItem.children != null) {
//apply same on every child
menuItem.children.forEach((childMenuItem: MenuItem) => {
//We remove the nested key and then use it as prefix for every child
this.translateMenuTitle(childMenuItem, PagesComponent.trimLastSelector(key));
});
}
}
/**
* Resolves the translation key for a menu item. The prefix must be supplied for every child menu item
* @param menuItem
* @param prefix
* @returns {string}
*/
private static getMenuItemKey(menuItem: MenuItem, prefix: string = 'menu'): string {
if (menuItem.key == null) {
throw new Error('Key not found');
}
const key = menuItem.key.toLowerCase();
if (menuItem.children != null) {
return prefix + '.' + key + '.' + key; //Translation is nested
}
return prefix + '.' + key;
}
/**
* Used to remove the nested key for translations
* @param key
* @returns {string}
*/
private static trimLastSelector(key: string): string {
const keyParts = key.split('.');
keyParts.pop();
return keyParts.join('.');
}
}
@MohamedGamil
Copy link

MohamedGamil commented Mar 14, 2018

At pages-menu.ts, line 1 you should import MenuItem interface instead.

Such that:
import { MenuItem } from '../@theme/custom-nebular/menu-item';

Then at line 3 change NbMenuItem to MenuItem, such that:

export const MENU_ITEMS: MenuItem[] = [

Thanks for this gist,
Much love <3

@dizco
Copy link
Author

dizco commented Apr 27, 2018

@MohamedGamil you are absolutely right! Somehow I introduced this typo when creating this gist... I have fixed it now! Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment