Configuración multiidioma, se lee un array del fichero config.json con los idiomas disponibles y busca el fichero correspondiente en locales, creado menu en la barra superior para cambiar de idioma

pull/72/head
Juan Manuel Bardallo 2026-04-23 14:12:23 +02:00
parent 944193478e
commit 2498d9faa8
7 changed files with 148 additions and 62 deletions

View File

@ -13,6 +13,6 @@ export class AppComponent {
this.translateService.use(savedLanguage);
}
ngOnInit() {
sessionStorage.setItem('language', 'es');
// Language is already handled in constructor
}
}

View File

@ -171,3 +171,33 @@ mat-toolbar button[mat-icon-button]:hover {
right: 8px;
}
}
.language-button {
display: flex !important;
align-items: center;
gap: 8px;
border: 1px solid #5f5f5f !important;
border-radius: 6px !important;
padding: 0 12px !important;
color: #495057 !important;
background: #fafafa !important;
transition: all 0.2s ease-in-out !important;
font-weight: 500 !important;
height: 40px !important;
}
.language-button:hover {
background-color: #f8f9fa !important;
border-color: #adb5bd !important;
}
.language-button mat-icon {
font-size: 20px;
width: 20px;
height: 20px;
margin: 0 !important;
}
.language-button .mat-icon:last-child {
margin-left: -4px !important;
}

View File

@ -8,67 +8,96 @@
matTooltipShowDelay="1000">
</span>
<div class="navbar-actions-row" *ngIf="!isSmallScreen">
<button routerLink="/commands-logs" mat-button>
<mat-icon class="trace-button" >notifications</mat-icon>
</button>
<div class="navbar-buttons-row">
<a class="ordinary-button download-agent-button" href="https://ognproject.evlt.uma.es/ogagent/" target="_blank" rel="noopener noreferrer"
[matTooltip]="'downloadOgAgent' | translate" matTooltipShowDelay="1000">
<mat-icon class="download-icon">download</mat-icon>
{{ 'downloadAgent' | translate }}
</a>
<button class="ordinary-button" (click)="showGlobalStatus()">
{{ 'GlobalStatus' | translate }}
@if (!isSmallScreen) {
<div class="navbar-actions-row">
<button routerLink="/commands-logs" mat-button>
<mat-icon class="trace-button" >notifications</mat-icon>
</button>
<button class="ordinary-button" *ngIf="auth.userCategory === 'super-admin'" [matMenuTriggerFor]="menu"
[matTooltip]="'manageUsersAndRolesDesc' | translate" matTooltipShowDelay="1000">
{{ 'Administration' | translate }}
</button>
<div class="navbar-buttons-row">
<a class="ordinary-button download-agent-button" href="https://ognproject.evlt.uma.es/ogagent/" target="_blank" rel="noopener noreferrer"
[matTooltip]="'downloadOgAgent' | translate" matTooltipShowDelay="1000">
<mat-icon class="download-icon">download</mat-icon>
{{ 'downloadAgent' | translate }}
</a>
<button class="ordinary-button" (click)="editUser()" *ngIf="auth.userCategory !== 'super-admin'"
[matTooltip]="'editUserTooltip' | translate" matTooltipShowDelay="1000">
{{ 'changePassword' | translate }}
</button>
<button class="ordinary-button" (click)="showGlobalStatus()">
{{ 'GlobalStatus' | translate }}
</button>
<button class="logout-button" (click)="logOut()" [matTooltip]="'logoutTooltip' | translate"
@if (auth.userCategory === 'super-admin') {
<button class="ordinary-button" [matMenuTriggerFor]="menu"
[matTooltip]="'manageUsersAndRolesDesc' | translate" matTooltipShowDelay="1000">
{{ 'Administration' | translate }}
</button>
}
@if (auth.userCategory !== 'super-admin') {
<button class="ordinary-button" (click)="editUser()"
[matTooltip]="'editUserTooltip' | translate" matTooltipShowDelay="1000">
{{ 'changePassword' | translate }}
</button>
}
<button mat-button [matMenuTriggerFor]="langMenu" class="language-button">
<mat-icon>language</mat-icon>
{{ 'labelLanguage' | translate }}
<mat-icon iconPositionEnd>arrow_drop_down</mat-icon>
</button>
<button class="logout-button" (click)="logOut()" [matTooltip]="'logoutTooltip' | translate"
matTooltipShowDelay="1000">
{{ 'logout' | translate }}
</button>
</div>
</div>
}
<mat-menu #langMenu="matMenu">
@for (lang of availableLanguages; track lang.code) {
<button mat-menu-item (click)="switchLanguage(lang.code)" [disabled]="getCurrentLanguage() === lang.code">
<span>{{ lang.label }}</span>
</button>
}
</mat-menu>
<!-- Menú desplegable para pantallas pequeñas -->
@if (isSmallScreen) {
<div class="isSmallScreenButtons">
<button class="trace-button" routerLink="/commands-logs" mat-button>
<mat-icon>notifications</mat-icon>
</button>
<button class="smallScreenMenubutton" mat-icon-button [matMenuTriggerFor]="smallScreenMenu" [matTooltip]="'labelOptions' | translate" matTooltipShowDelay="1000">
<mat-icon>menu</mat-icon>
</button>
<mat-menu #smallScreenMenu="matMenu">
<a mat-menu-item href="https://ognproject.evlt.uma.es/ogagent/" target="_blank" rel="noopener noreferrer">
<mat-icon>download</mat-icon>
{{ 'downloadAgent' | translate }}
</a>
<button mat-menu-item (click)="showGlobalStatus()">
{{ 'GlobalStatus' | translate }}
</button>
@if (auth.userCategory === 'super-admin') {
<button mat-menu-item [matMenuTriggerFor]="menu">
{{ 'Administration' | translate }}
</button>
<button mat-menu-item (click)="editUser()">
{{ 'changePassword' | translate }}
</button>
}
<mat-divider></mat-divider>
<button mat-menu-item [matMenuTriggerFor]="langMenu">
<mat-icon>language</mat-icon>
{{ 'labelLanguage' | translate }}
</button>
</mat-menu>
<button class="logout-button" routerLink="/auth/login" [matTooltip]="'logoutTooltip' | translate"
matTooltipShowDelay="1000">
{{ 'logout' | translate }}
</button>
</div>
</div>
<!-- Menú desplegable para pantallas pequeñas -->
<div *ngIf="isSmallScreen" class="isSmallScreenButtons">
<button class="trace-button" routerLink="/commands-logs" mat-button>
<mat-icon>notifications</mat-icon>
</button>
<button class="smallScreenMenubutton" mat-icon-button [matMenuTriggerFor]="smallScreenMenu" [matTooltip]="'labelOptions' | translate" matTooltipShowDelay="1000">
<mat-icon>menu</mat-icon>
</button>
<mat-menu #smallScreenMenu="matMenu">
<a mat-menu-item href="https://ognproject.evlt.uma.es/ogagent/" target="_blank" rel="noopener noreferrer">
<mat-icon>download</mat-icon>
{{ 'downloadAgent' | translate }}
</a>
<button mat-menu-item (click)="showGlobalStatus()">
{{ 'GlobalStatus' | translate }}
</button>
<button mat-menu-item *ngIf="auth.userCategory === 'super-admin'" [matMenuTriggerFor]="menu">
{{ 'Administration' | translate }}
</button>
<button mat-menu-item *ngIf="auth.userCategory === 'super-admin'" (click)="editUser()">
{{ 'changePassword' | translate }}
</button>
</mat-menu>
<button class="logout-button" routerLink="/auth/login" [matTooltip]="'logoutTooltip' | translate"
matTooltipShowDelay="1000">
{{ 'logout' | translate }}
</button>
</div>
}
<mat-menu #menu="matMenu">
<button mat-menu-item routerLink="/users" [matTooltip]="'viewAndManageUsers' | translate"

View File

@ -1,9 +1,11 @@
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { Component, EventEmitter, OnInit, Output, inject } from '@angular/core';
import { ChangePasswordModalComponent } from '../../components/admin/users/users/change-password-modal/change-password-modal.component';
import { MatDialog } from "@angular/material/dialog";
import { GlobalStatusComponent } from 'src/app/components/global-status/global-status.component';
import { BreakpointObserver } from '@angular/cdk/layout';
import { AuthService } from '@services/auth.service';
import { TranslateService } from '@ngx-translate/core';
import { ConfigService } from '@services/config.service';
@Component({
selector: 'app-header',
@ -12,6 +14,8 @@ import { AuthService } from '@services/auth.service';
})
export class HeaderComponent implements OnInit {
private translate = inject(TranslateService);
private config = inject(ConfigService);
isSuperAdmin: boolean = false;
isSmallScreen: boolean = false;
@ -33,6 +37,14 @@ export class HeaderComponent implements OnInit {
})
}
get availableLanguages() {
const langs = this.config.languages;
return Object.keys(langs).map(code => ({
code,
label: langs[code]
}));
}
editUser() {
const dialogRef = this.dialog.open(ChangePasswordModalComponent, {
data: { user: this.auth.username, uuid: this.auth.uuid },
@ -50,4 +62,13 @@ export class HeaderComponent implements OnInit {
logOut() {
this.auth.logout();
}
switchLanguage(lang: string) {
this.translate.use(lang);
localStorage.setItem('language', lang);
}
getCurrentLanguage(): string {
return this.translate.currentLang || 'es';
}
}

View File

@ -26,14 +26,18 @@ export class ConfigService {
}
get apiUrl(): string {
return this.config.apiUrl;
return this.config?.apiUrl;
}
get mercureUrl(): string {
return this.config.mercureUrl;
return this.config?.mercureUrl;
}
get logUrl(): string {
return this.config.logUrl;
return this.config?.logUrl;
}
get languages(): { [key: string]: string } {
return this.config?.languages || { "es": "Español", "en": "English" };
}
}

View File

@ -880,8 +880,9 @@
"labelValue": "Value",
"labelVariable": "Variable",
"labelWeekDays": "Days of the week",
"langEnglish": "English",
"langSpanish": "Spanish",
"labelLanguage": "Language",
"langEn": "English",
"langEs": "Spanish",
"Legend": "Legend",
"limpiarAcciones": "Clear actions",
"linuxOption": "LINUX",

View File

@ -866,8 +866,9 @@
"labelValue": "Valor",
"labelVariable": "Variable",
"labelWeekDays": "Días de la semana",
"langEnglish": "Inglés",
"langSpanish": "Español",
"labelLanguage": "Idioma",
"langEn": "Inglés",
"langEs": "Español",
"Legend": "Leyenda",
"limpiarAcciones": "Limpiar acciones",
"linuxOption": "LINUX",